SpringSecurity角色權(quán)限控制(SpringBoot+SpringSecurity+JWT)
一、項(xiàng)目介紹
通過springboot整合jwt和security,以用戶名/密碼的方式進(jìn)行認(rèn)證和授權(quán)。認(rèn)證通過jwt+數(shù)據(jù)庫的,授權(quán)這里使用了兩種方式,分別是SpringSecurity自帶的hasRole方法+SecurityConfig 和 我們自定義的permission+@PreAuthorize注解。
二、SpringSecurity簡(jiǎn)介
SpringSecurity中的幾個(gè)重要組件:
1.SecurityContextHolder(class)
用來存儲(chǔ)和獲取當(dāng)前線程關(guān)聯(lián)的 SecurityContext 對(duì)象的類。
![[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-ku2An95n-1683728698707)(E:/Blog/lansg/source/img/1683186758072-ccd6a67a-c2c5-4ec7-aca3-b42404ce8277.png)]](http://img.jbzj.com/file_images/article/202405/2024050711265639.png)
其中有兩種 SecurityContext 模式:
- MODE_THREADLOCAL:將 SecurityContext 對(duì)象存儲(chǔ)到當(dāng)前線程中,只在當(dāng)前線程中可見。多線程時(shí),每個(gè)線程的 SecurityContext 對(duì)象都是獨(dú)立的。
- MODE_INHERITABLETHREADLOCAL:將 SecurityContext 對(duì)象存儲(chǔ)到當(dāng)前線程中,對(duì)當(dāng)前線程和子線程都可見。也就是說,在當(dāng)前線程中存儲(chǔ)的 SecurityContext 對(duì)象可以被傳遞給子線程使用。
表示用戶已通過身份驗(yàn)證的最簡(jiǎn)單方法就是設(shè)置 SecurityContextHolder!
2.SecurityContext(Interface)
用來存儲(chǔ)當(dāng)前已經(jīng)被認(rèn)證的用戶,包含了當(dāng)前執(zhí)行操作的線程上下文信息以及用戶認(rèn)證和授權(quán)信息。包含Authentication。
![[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-KFfG9auG-1683728698708)(E:/Blog/lansg/source/img/1683186616655-7d1408b0-f5aa-4a06-ae7e-417d63c3fe94.png)]](http://img.jbzj.com/file_images/article/202405/2024050711265640.png)
3.Authentication(Interface)
存儲(chǔ)了當(dāng)前正在執(zhí)行操作的用戶的身份驗(yàn)證信息,包括用戶名、密碼、權(quán)限,可以作為AuthenticationManager的輸入,它包含principal、credentials、authorities。
- principal:用戶的標(biāo)識(shí)。通常情況下是UserDetails接口的一個(gè)實(shí)例。
- credentials:用戶的密碼。多數(shù)情況下,為確保密碼不被泄露,會(huì)在用戶身份驗(yàn)證之后被清除。
- authorities:用戶擁有的權(quán)限。

Authentication 接口的常用實(shí)現(xiàn)類有以下幾種:
- AnonymousAuthenticationToken:匿名用戶的身份驗(yàn)證信息。
- UsernamePasswordAuthenticationToken:用戶名/密碼的身份驗(yàn)證信息。
- RememberMeAuthenticationToken:用于“記住我”功能的身份驗(yàn)證信息。
- PreAuthenticatedAuthenticationToken:基于預(yù)先認(rèn)證信息的身份驗(yàn)證。
通常情況下,用戶在進(jìn)行登錄時(shí)需要通過身份驗(yàn)證,當(dāng)身份驗(yàn)證成功時(shí),就會(huì)通過 Authentication 接口封裝用戶的身份信息。在后續(xù)的操作中,認(rèn)證后的用戶可以通過 SecurityContextHolder 獲取 Authentication 對(duì)象,并根據(jù)其中的信息獲得用戶的身份信息及相應(yīng)的權(quán)限等。
對(duì)比SecurityContext和Authentication:
Authentication 是一個(gè)封裝了用戶身份認(rèn)證信息的對(duì)象,表示用戶已經(jīng)通過了驗(yàn)證。
SecurityContext 則是一個(gè)上下文類對(duì)象,用于保存和獲取當(dāng)前線程關(guān)聯(lián)的上下文信息,包括了 Authentication 對(duì)象。

4.AuthenticationManager(Interface)
定義了用戶身份驗(yàn)證的api接口(例如將用戶名和密碼和數(shù)據(jù)庫進(jìn)行比對(duì))??梢越邮找粋€(gè)Authentication對(duì)象作為入?yún)?,?yàn)證成功后會(huì)返回已被驗(yàn)證的Authentication對(duì)象。

5.GrantedAuthority(Interface)
授權(quán)信息以GrantedAuthority的形式存儲(chǔ)在Authentication對(duì)象中,GrantedAuthority接口表示一個(gè)授權(quán)(權(quán)限)對(duì)象,包含一個(gè)字符串類型的授權(quán)名字(authority name)。授權(quán)名字通常是一個(gè)表示權(quán)限的字符串,例如"ROLE_ADMIN"、"ROLE_USER"等
二、整理思路
- 搭建springboot項(xiàng)目,導(dǎo)入相關(guān)依賴
- 在數(shù)據(jù)庫導(dǎo)入sql創(chuàng)建用戶表
- 創(chuàng)建幾個(gè)關(guān)于User的對(duì)象便于數(shù)據(jù)傳輸
- dao層開發(fā)(對(duì)用戶信息增刪改查)
- 實(shí)現(xiàn)UserDetails接口和UserDetailService接口
- 自定義實(shí)現(xiàn)校驗(yàn)token的攔截器JwtAuthenticationTokenFilter
- 自定義實(shí)現(xiàn)用戶登錄校驗(yàn)的攔截器JWTAuthenticationFilter
- service層開發(fā)(包括PermissionService和UserService)
- 創(chuàng)建測(cè)試Controller
- 實(shí)現(xiàn)SpringSecurity的配置類SecurityConfig
- 通過postman進(jìn)行測(cè)試
三、具體實(shí)現(xiàn)步驟
1.項(xiàng)目主要相關(guān)依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
2.用戶表
創(chuàng)建一個(gè)名為security_jwt_demo的數(shù)據(jù)庫,導(dǎo)入項(xiàng)目根目錄下/db/db.sql文件即可。
3.項(xiàng)目中用到的幾個(gè)user相關(guān)對(duì)象
(1)User實(shí)體
對(duì)應(yīng)數(shù)據(jù)庫中的user表
@Data
public class User {
private Long id;
private String username;
private String password;
private String permission;
private String role;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", permission='" + permission + '\'' +
", role='" + role + '\'' +
'}';
}
}
(2)LoginUser
UserDetails的實(shí)現(xiàn)類,使用用戶名/密碼驗(yàn)證時(shí)需要用到其作為返回值。這個(gè)類中包含了用戶名、密碼和當(dāng)前登錄用戶所具備的權(quán)限。
@Data
public class LoginUser implements UserDetails {
private Long id;
private String username;
private String password;
//通過自定義方式進(jìn)行授權(quán)
private Set<String> permissions = new HashSet<String>();
//通過springSecurity進(jìn)行授權(quán)
private Collection<? extends GrantedAuthority> authorities;
public LoginUser(){}
public LoginUser(User user,Collection<? extends GrantedAuthority> authorities) {
id = user.getId();
username = user.getUsername();
password = user.getPassword();
permissions.add(user.getPermission());
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
(3)UserVO
主要用來登錄時(shí)從輸入流中獲取登錄用戶的信息,對(duì)應(yīng)了前端傳遞的參數(shù),包括用戶名、密碼、記住我等屬性。
@Data
public class UserVO {
private String username;
private String password;
private Integer rememberMe;
}
4.dao層開發(fā)
創(chuàng)建mapper接口并配置對(duì)應(yīng)的mapper.xml
@Mapper
public interface UserMapper {
//根據(jù)用戶名獲取用戶
User getByName(String username);
//根據(jù)用戶id獲取用戶權(quán)限
List<String> getPermissionById(Long id);
//新增一個(gè)用戶
int insertUser(User user);
}
5.實(shí)現(xiàn)UserDetail接口和UserDetailService接口
首先說一下為什么要實(shí)現(xiàn)這兩個(gè)接口。
SpringSecurity提供了多種身份驗(yàn)證的方式,在這里我們使用的是用戶名/密碼的方式進(jìn)行驗(yàn)證,而如果要使用這種方式進(jìn)行驗(yàn)證的話,我們需要實(shí)現(xiàn)UserDetailService接口中的loadUserByUsername方法,這個(gè)方法用來從數(shù)據(jù)庫中進(jìn)行查詢用戶,然后和傳入的用戶密碼進(jìn)行比對(duì)。這個(gè)方法會(huì)返回一個(gè)UserDetails對(duì)象。
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.getByName(username);
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
return new LoginUser(user,authorities);
}
}
對(duì)于UserDetailService接口,SpringSecurity提供了基于內(nèi)存和JDBC的兩種驗(yàn)證方式,默認(rèn)是JDBC的方式。我們也可以通過自定義實(shí)現(xiàn)UserDetailService接口,來達(dá)到自定義身份驗(yàn)證的結(jié)果。這里我們使用的是自定義身份驗(yàn)證的方式。
對(duì)于UserDetails,在Spring Security中,UserDetails接口是表示用戶信息的規(guī)范。該接口表示應(yīng)用程序中的用戶,并提供有關(guān)用戶的基本信息,如用戶名、密碼、角色、權(quán)限等,因此我們需要有一個(gè)類似用戶的對(duì)象來實(shí)現(xiàn)該接口(LoginUser)。
6.JwtAuthenticationTokenFilter
檢驗(yàn)用戶token的過濾器。對(duì)于客戶端發(fā)出的請(qǐng)求,首先對(duì)用戶的token進(jìn)行校驗(yàn),如果token不合法表示當(dāng)前用戶未登錄,繼續(xù)執(zhí)行其他過濾器的邏輯;如果token合法則設(shè)置SecurityContextHolder表示用戶已被認(rèn)證。
/**
* token過濾器 驗(yàn)證token有效性
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
UserMapper userMapper;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String token = request.getHeader(JwtTokenUtil.TOKEN_HEADER);
if (StringUtils.isBlank(token) || !token.startsWith(JwtTokenUtil.TOKEN_PREFIX)){
chain.doFilter(request,response);
return;
}
try {
//如果能獲取到token則Authentication進(jìn)行設(shè)置,表示已認(rèn)證
SecurityContextHolder.getContext().setAuthentication(getAuthentication(token));
} catch (Exception e) {
e.printStackTrace();
}
//繼續(xù)執(zhí)行其他過濾器的邏輯
chain.doFilter(request,response);
}
private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) throws Exception {
String token = tokenHeader.replace(JwtTokenUtil.TOKEN_PREFIX,"");
//判斷token是否過期
boolean expiration = JwtTokenUtil.isExpiration(token);
if (expiration){
throw new Exception("過期了");
}else{
String username = JwtTokenUtil.getUsername(token);
User user = userMapper.getByName(username);
List<String> permissions = userMapper.getPermissionById(user.getId());
LoginUser loginUser = new LoginUser(user, Collections.singleton(new SimpleGrantedAuthority(user.getRole())));
loginUser.setPermissions(new HashSet<>(permissions));
//新建一個(gè)UsernamePasswordAuthenticationToken用來設(shè)置Authentication
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
return authenticationToken;
}
}
}
7.JWTAuthenticationFilter
用戶登錄時(shí)對(duì)用戶名密碼進(jìn)行校驗(yàn)的過濾器,在token校驗(yàn)過濾器之后執(zhí)行。在該過濾器中會(huì)對(duì)用戶名密碼進(jìn)行比對(duì),校驗(yàn)成功后返回一個(gè)token給客戶端,下次客戶端訪問時(shí)在請(qǐng)求頭帶上此token代表該用戶已經(jīng)被認(rèn)證。
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private ThreadLocal<Integer> rememberMe = new ThreadLocal<>();
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
super.setFilterProcessesUrl("/auth/login");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// 從輸入流中獲取到登錄的信息
try {
UserVO vo = new ObjectMapper().readValue(request.getInputStream(), UserVO.class);
rememberMe.set(vo.getRememberMe() == null ? 0 : vo.getRememberMe());
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(vo.getUsername(), vo.getPassword(), new ArrayList<>())
);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
// 成功驗(yàn)證后調(diào)用的方法
// 如果驗(yàn)證成功,就生成token并返回
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
LoginUser loginUser = (LoginUser) authResult.getPrincipal();
System.out.println("loginUser:" + loginUser.toString());
boolean isRemember = rememberMe.get() == 1;
String role = "";
String token = JwtTokenUtil.createToken(loginUser.getUsername(), role, isRemember);
/* 返回創(chuàng)建成功的token
但是這里創(chuàng)建的token只是單純的token
按照jwt的規(guī)定,最后請(qǐng)求的時(shí)候應(yīng)該是 `Bearer token`*/
response.setHeader("token", JwtTokenUtil.TOKEN_PREFIX + token);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
response.getWriter().write("authentication failed, reason: " + failed.getMessage());
}
}
8.service層開發(fā)
由于業(yè)務(wù)邏輯比較簡(jiǎn)單,我們?cè)趕ervice層中主要實(shí)現(xiàn)自定義授權(quán)的邏輯,用戶相關(guān)的Service不做實(shí)現(xiàn)。
自定義授權(quán)的實(shí)現(xiàn)如下,首先在數(shù)據(jù)庫的user表中有個(gè)string類型的permission字段,代表用戶所擁有的權(quán)限。在進(jìn)行授權(quán)時(shí)檢查用戶權(quán)限屬性是否包含該權(quán)限,如果包含則表示當(dāng)前用戶具有訪問權(quán)限。
/**
* 自定義權(quán)限實(shí)現(xiàn),ss取自SpringSecurity首字母
*/
@Service("ss")
public class PermissionService {
public boolean hasPer(String permission) throws Exception {
if (StringUtils.isBlank(permission)){
return false;
}
LoginUser loginUser = SecurityUtil.getLoginUser();
if (loginUser == null || CollectionUtils.isEmpty(loginUser.getPermissions())) {
return false;
}
return loginUser.getPermissions().contains(StringUtils.trim(permission));
}
}
9.Controller層開發(fā)
我們用到的Controller主要有兩個(gè),一個(gè)是用戶相關(guān)的,一個(gè)是進(jìn)行測(cè)試的接口。
對(duì)于我們進(jìn)行授權(quán)測(cè)試的接口,在使用自定義授權(quán)邏輯時(shí)(PermissionService),要配合@PreAuthorize注解實(shí)現(xiàn)(createJob方法),對(duì)應(yīng)的JobController如下:
@RestController
@RequestMapping("/jobs")
public class JobController {
@GetMapping("/list")
public String listJobs(){
System.out.println("接收到請(qǐng)求...");
return "展示所有任務(wù)";
}
//通過PermissionService自定義授權(quán)實(shí)現(xiàn)
@PostMapping("/create")
@PreAuthorize("@ss.hasPer('job:add')")
public String createJob(){
return "創(chuàng)建一個(gè)新任務(wù)";
}
//通過SpringSecurity配合用戶角色(role字段)實(shí)現(xiàn)權(quán)限管理
@DeleteMapping("/delete")
public String deleteJob(){
return "刪除一個(gè)任務(wù)";
}
}
對(duì)于用戶相關(guān)的Controller,我們只需要寫一個(gè)注冊(cè)方法就行了,如下所示:
@RestController
@RequestMapping("/")
public class UserController {
@Autowired
UserMapper userMapper;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@PostMapping("/register")
public String register(@RequestBody Map<String,String> registerUser){
User user = new User();
user.setUsername(registerUser.get("username"));
//對(duì)密碼進(jìn)行一下加密
user.setPassword(bCryptPasswordEncoder.encode(registerUser.get("password")));
user.setPermission(registerUser.get("permission"));
user.setRole(registerUser.get("role"));
userMapper.insertUser(user);
return user.toString();
}
}
為什么不需要注冊(cè)接口呢?是因?yàn)閁sernamePasswordAuthenticationFilter已經(jīng)幫我們實(shí)現(xiàn)了,默認(rèn)是"/login"
public UsernamePasswordAuthenticationFilter() {
super(new AntPathRequestMatcher("/login", "POST"));
}
這里我們也可以對(duì)這個(gè)路徑進(jìn)行修改,如下所示:
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
super.setFilterProcessesUrl("/auth/login");
}
10.通過SecurityConfig類對(duì)SpringSecurity進(jìn)行配置
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired
@Qualifier("userDetailServiceImpl")
UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
// 測(cè)試用資源,需要驗(yàn)證了的用戶才能訪問
.antMatchers("/jobs/create").authenticated()
//只有角色為admin的用戶才能進(jìn)行刪除
.antMatchers(HttpMethod.DELETE,"/jobs/delete").hasRole("ADMIN")
// 其他請(qǐng)求都放行了
.anyRequest().permitAll()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
// 不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//將驗(yàn)證token的過濾器添加在驗(yàn)證用戶名/密碼的過濾器之前
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
CorsConfigurationSource corsConfigurationSource(){
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**",new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
到這里就全部完成了!讓我們測(cè)試一下是否生效。
11.postman測(cè)試
這是數(shù)據(jù)庫表中原有的角色和權(quán)限:

(1)測(cè)試注冊(cè)接口

可以看到是可以注冊(cè)成功的,但是我們這里使用原有user1和user2進(jìn)行權(quán)限測(cè)試(偷個(gè)懶)
(2)測(cè)試登錄接口
由于我們之前將原有的登錄接口從"/login"改為了"/auth/login",這里需要注意一下。

登錄成功后的ResponseBody是空的,響應(yīng)頭中有token代表已經(jīng)登錄成功了。我們需要從header中獲取該token,后續(xù)請(qǐng)求需要用到。這里展示了user2,user1也是一樣的。

(3)測(cè)試創(chuàng)建任務(wù)接口
由于創(chuàng)建任務(wù)需要"job:add"權(quán)限,查看數(shù)據(jù)庫user2是有該權(quán)限的,user1沒有。
將剛才登錄獲得的token添加到參數(shù)中:

然后發(fā)現(xiàn)就可以創(chuàng)建成功了

(4)測(cè)試刪除任務(wù)接口
刪除任務(wù)需要用戶角色是admin,故user2是無法進(jìn)行刪除的。

(5)我們按照剛才的流程對(duì)user1進(jìn)行測(cè)試,來達(dá)到對(duì)比的效果。
登錄:

創(chuàng)建任務(wù):

刪除任務(wù):

對(duì)于查詢接口不需要進(jìn)行認(rèn)證和授權(quán),也就是說不需要登錄就能訪問:

到此這篇關(guān)于SpringSecurity角色權(quán)限控制(SpringBoot+SpringSecurity+JWT)的文章就介紹到這了,更多相關(guān)SpringSecurity角色權(quán)限內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot集成?JWT實(shí)現(xiàn)用戶登錄認(rèn)證的項(xiàng)目實(shí)踐
- SpringBoot結(jié)合JWT實(shí)現(xiàn)用戶登錄、注冊(cè)、鑒權(quán)
- springBoot整合jwt實(shí)現(xiàn)token令牌認(rèn)證的示例代碼
- springboot中通過jwt令牌校驗(yàn)及前端token請(qǐng)求頭進(jìn)行登錄攔截實(shí)戰(zhàn)記錄
- SpringBoot整合JWT(JSON?Web?Token)生成token與驗(yàn)證的流程及示例
- Springboot+jwt實(shí)現(xiàn)在線用戶功能(示例代碼)
相關(guān)文章
Spring?Security中如何獲取AuthenticationManager對(duì)象
有時(shí)需要使用AuthenticationManager(以下簡(jiǎn)稱Manager)對(duì)象,可是這個(gè)對(duì)象不是Bean,沒有直接保存在Spring的Bean庫中,那么如何獲取Spring Security中的這個(gè)對(duì)象呢,需要的朋友可以參考下2022-11-11
關(guān)于Spring中Bean的創(chuàng)建進(jìn)行更多方面的控制
今天小編就為大家分享一篇關(guān)于關(guān)于Spring中Bean的創(chuàng)建進(jìn)行更多方面的控制,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-01-01
SpringCloud分布式鏈路追蹤組件Sleuth配置詳解
這篇文章主要介紹了SpringCloud鏈路追蹤組件Sleuth配置方法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-11-11
mybatis如何對(duì)大量數(shù)據(jù)的游標(biāo)查詢
這篇文章主要介紹了mybatis如何對(duì)大量數(shù)據(jù)的游標(biāo)查詢問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
Java?對(duì)象深拷貝工具類的實(shí)現(xiàn)
本文主要介紹了Java?對(duì)象深拷貝工具類的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Spring中的@Autowired注解深入解析與實(shí)戰(zhàn)指南
本文介紹了Spring框架中的@Autowired注解,詳細(xì)講解了其基本用法、高級(jí)用法以及實(shí)際應(yīng)用場(chǎng)景,通過@Autowired注解,Spring容器可以自動(dòng)將依賴的Bean注入到目標(biāo)Bean中,從而簡(jiǎn)化代碼并提高可維護(hù)性,需要的朋友可以參考下2024-11-11
mybatis配置Mapper.xml文件時(shí)遇到的問題及解決
這篇文章主要介紹了mybatis配置Mapper.xml文件時(shí)遇到的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01

