spring security如何擴(kuò)展自定義登錄
背景
spring security 默認(rèn)給我們提供了一套用戶名密碼登錄的的邏輯實(shí)現(xiàn),在很多時(shí)候根本不滿足我們實(shí)際開發(fā)的要求,所以我們經(jīng)常需要對(duì)它認(rèn)證模塊進(jìn)行擴(kuò)展,那么如何擴(kuò)展我們的認(rèn)證方式呢,這篇文章將會(huì)給你一個(gè)較為完整的解答。
認(rèn)證原理
Spring Security使用了一種基于過(guò)濾器鏈的認(rèn)證原理來(lái)保護(hù)應(yīng)用程序。它提供了一組過(guò)濾器,這些過(guò)濾器按照特定的順序?qū)γ總€(gè)請(qǐng)求進(jìn)行處理。
認(rèn)證過(guò)程中的主要步驟如下:
- 用戶發(fā)送認(rèn)證請(qǐng)求到應(yīng)用程序。
- 應(yīng)用程序?qū)⒄?qǐng)求發(fā)送給Spring Security的過(guò)濾器鏈。
- 過(guò)濾器鏈依次處理請(qǐng)求,直到找到可以處理該請(qǐng)求的過(guò)濾器。
- 找到處理請(qǐng)求的過(guò)濾器后,該過(guò)濾器會(huì)驗(yàn)證用戶的憑證(如用戶名和密碼)。
- 如果憑證有效,則生成一個(gè)已認(rèn)證的安全上下文,并將其保存在Spring Security的上下文存儲(chǔ)中。
- 如果憑證無(wú)效,則返回認(rèn)證失敗的信息給用戶。
- 認(rèn)證成功后,用戶可以繼續(xù)訪問(wèn)受保護(hù)的資源。
在認(rèn)證過(guò)程中,Spring Security還提供了靈活的配置選項(xiàng),可以根據(jù)特定的需求進(jìn)行自定義配置,例如使用不同的認(rèn)證提供程序、自定義身份驗(yàn)證邏輯等。
總結(jié)起來(lái),Spring Security的認(rèn)證原理是通過(guò)一組過(guò)濾器鏈來(lái)處理認(rèn)證請(qǐng)求,驗(yàn)證用戶憑證并生成認(rèn)證的安全上下文,以保護(hù)應(yīng)用程序的資源。
具體實(shí)現(xiàn)原理
Spring Security的認(rèn)證實(shí)現(xiàn)原理主要涉及以下幾個(gè)核心概念和組件:
- 用戶提供的憑證:用戶在進(jìn)行認(rèn)證時(shí),需要提供其身份憑證,如用戶名和密碼。
- 認(rèn)證提供程序(Authentication Provider):認(rèn)證提供程序是Spring Security中的重要組件,負(fù)責(zé)驗(yàn)證用戶提供的憑證。它使用用戶提供的憑證與系統(tǒng)中存儲(chǔ)的憑證進(jìn)行比對(duì),并決定是否通過(guò)認(rèn)證。Spring
- Security提供了多種內(nèi)置的認(rèn)證提供程序,如基于數(shù)據(jù)庫(kù)的JDBC認(rèn)證提供程序、LDAP認(rèn)證提供程序、InMemory認(rèn)證提供程序等。同時(shí)也支持自定義認(rèn)證提供程序。
- 用戶詳情服務(wù)(UserDetailsService):用戶詳情服務(wù)是Spring Security中的接口,負(fù)責(zé)獲取用戶的詳細(xì)信息,如用戶的權(quán)限、角色等。認(rèn)證提供程序在驗(yàn)證用戶憑證后,會(huì)使用用戶詳情服務(wù)獲取用戶的詳細(xì)信息,并構(gòu)建一個(gè)認(rèn)證對(duì)象(Authentication)。
- 認(rèn)證對(duì)象(Authentication):認(rèn)證對(duì)象是Spring Security中表示已認(rèn)證用戶的對(duì)象。它包含了用戶的身份信息、憑證信息、權(quán)限信息等。認(rèn)證對(duì)象由認(rèn)證提供程序生成,并將其保存在SecurityContextHolder的上下文存儲(chǔ)中。
- 認(rèn)證過(guò)濾器鏈(Authentication Filter Chain):認(rèn)證過(guò)濾器鏈?zhǔn)荢pring Security中的過(guò)濾器組成的鏈條,負(fù)責(zé)處理認(rèn)證請(qǐng)求。每個(gè)過(guò)濾器都會(huì)對(duì)請(qǐng)求進(jìn)行處理,并根據(jù)需要進(jìn)行認(rèn)證、授權(quán)和其他安全操作。在認(rèn)證過(guò)程中,認(rèn)證過(guò)濾器鏈會(huì)根據(jù)請(qǐng)求的URL匹配合適的過(guò)濾器進(jìn)行處理。
- 安全上下文(Security Context):安全上下文是Spring Security中用于保存已認(rèn)證用戶信息的容器。它以ThreadLocal的方式存儲(chǔ),可以通過(guò)SecurityContextHolder來(lái)訪問(wèn)和操作。安全上下文中保存了當(dāng)前的認(rèn)證對(duì)象,可以在應(yīng)用程序的任何地方獲取已認(rèn)證用戶的信息。
總結(jié)起來(lái),Spring Security的認(rèn)證實(shí)現(xiàn)原理是通過(guò)認(rèn)證提供程序驗(yàn)證用戶提供的憑證,使用用戶詳情服務(wù)獲取用戶的詳細(xì)信息,并構(gòu)建一個(gè)認(rèn)證對(duì)象,然后將該認(rèn)證對(duì)象保存在安全上下文中。
認(rèn)證過(guò)濾器鏈負(fù)責(zé)處理認(rèn)證請(qǐng)求,并根據(jù)需要進(jìn)行認(rèn)證、授權(quán)和其他安全操作。
通過(guò)這種方式,Spring Security實(shí)現(xiàn)了對(duì)應(yīng)用程序進(jìn)行認(rèn)證和授權(quán)的功能。
如何實(shí)現(xiàn)自定義認(rèn)證的功能
要自定義Spring Security的認(rèn)證模塊,你可以按照以下步驟進(jìn)行:
- 創(chuàng)建一個(gè)自定義的認(rèn)證提供程序(Authentication Provider)類,該類實(shí)現(xiàn)了
org.springframework.security.authentication.AuthenticationProvider接口。在該類中,你可以編寫你自己的認(rèn)證邏輯,比如驗(yàn)證用戶名和密碼是否匹配。 - 實(shí)現(xiàn)
UserDetailsService接口來(lái)獲取用戶的詳細(xì)信息。你可以根據(jù)自己的需求,從數(shù)據(jù)庫(kù)、LDAP等數(shù)據(jù)源中獲取用戶信息,并返回一個(gè)UserDetails對(duì)象。 - 在配置類(通常是繼承自
WebSecurityConfigurerAdapter的類)中,覆蓋configure(AuthenticationManagerBuilder auth)方法。在該方法中,你可以指定使用你自定義的認(rèn)證提供程序和用戶詳情服務(wù)來(lái)進(jìn)行認(rèn)證。 - 在上述配置類中,覆蓋
configure(HttpSecurity http)方法來(lái)配置認(rèn)證過(guò)濾器鏈。你可以根據(jù)需要添加和配置各種過(guò)濾器,例如表單登錄過(guò)濾器、基于Token的認(rèn)證過(guò)濾器等。
下面根據(jù)微信小程序登錄來(lái)實(shí)現(xiàn)一個(gè)自定義模塊的接口:
定義token信息類
public class JsCodeAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 5615450055779559101L;
private String code;
/**
* Creates a token with the supplied array of authorities.
*
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the principal
* represented by this authentication object.
*/
public JsCodeAuthenticationToken(Collection<? extends GrantedAuthority> authorities, String code) {
super(authorities);
this.code = code;
}
public JsCodeAuthenticationToken(String code) {
this(Collections.emptyList(), code);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return code;
}
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException(
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
}
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
}
}從代碼中我們可以看出我們需要?jiǎng)?chuàng)建一個(gè)相關(guān)的token類來(lái)繼承 AbstractAuthenticationToken 類,并實(shí)現(xiàn)相關(guān)的方法
AbstractAuthenticationToken 的定義
- Spring Security框架中的一個(gè)抽象類,用于表示身份驗(yàn)證請(qǐng)求令牌。它用于封裝用戶憑據(jù)或其他必要的信息來(lái)進(jìn)行用戶身份驗(yàn)證。
- AbstractAuthenticationToken的子類負(fù)責(zé)提供特定的身份驗(yàn)證細(xì)節(jié),例如用戶名和密碼、基于令牌的身份驗(yàn)證令牌等。這些子類通常包含獲取器和設(shè)置器,用于訪問(wèn)和修改身份驗(yàn)證細(xì)節(jié)。
- AbstractAuthenticationToken還提供了一組方法來(lái)管理身份驗(yàn)證狀態(tài),例如設(shè)置已認(rèn)證標(biāo)志、檢索與已認(rèn)證用戶關(guān)聯(lián)的權(quán)限以及管理與身份驗(yàn)證過(guò)程相關(guān)的其他詳細(xì)信息。
AbstractAuthenticationToken 的工作原理
- 當(dāng)用戶請(qǐng)求進(jìn)行身份驗(yàn)證時(shí),Spring Security將創(chuàng)建一個(gè)實(shí)現(xiàn)AbstractAuthenticationToken的具體子類對(duì)象,并將其中的身份驗(yàn)證信息進(jìn)行填充。然后,該身份驗(yàn)證令牌將被傳遞給身份驗(yàn)證管理器進(jìn)行進(jìn)一步的身份驗(yàn)證處理。
- 身份驗(yàn)證管理器將檢查身份驗(yàn)證令牌,并根據(jù)所配置的身份驗(yàn)證策略和安全規(guī)則,對(duì)用戶進(jìn)行身份驗(yàn)證。在身份驗(yàn)證過(guò)程中,身份驗(yàn)證管理器可能會(huì)調(diào)用相關(guān)的身份驗(yàn)證提供者,比如用戶名密碼身份驗(yàn)證提供者或令牌身份驗(yàn)證提供者,來(lái)驗(yàn)證用戶的憑據(jù)信息。
- 一旦用戶通過(guò)身份驗(yàn)證,身份驗(yàn)證管理器將更新AbstractAuthenticationToken中的已認(rèn)證標(biāo)志和權(quán)限信息,并將其返回給應(yīng)用程序。在后續(xù)的請(qǐng)求中,應(yīng)用程序可以根據(jù)需要訪問(wèn)身份驗(yàn)證令牌中的身份驗(yàn)證信息和權(quán)限信息,以實(shí)現(xiàn)不同的業(yè)務(wù)邏輯和訪問(wèn)控制。
定義一個(gè)接收參數(shù)的filter
@Slf4j
public class JsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static String jsCode = "code";
private static boolean postOnly = true;
protected JsCodeAuthenticationFilter(WechatProperties properties) {
super(new AntPathRequestMatcher(properties.getAuthUrl(), "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if (postOnly && !request.getMethod().equalsIgnoreCase("post")) {
throw new AuthenticationServiceException("該接口不支持:" + request.getMethod());
}
String code = obtainCode(request);
code = code.trim();
log.info("得到的code:{}", code);
JsCodeAuthenticationToken authenticationTokenRequest = new JsCodeAuthenticationToken(code);
setDetails(request, authenticationTokenRequest);
return this.getAuthenticationManager().authenticate(authenticationTokenRequest);
}
public String obtainCode(HttpServletRequest request) {
if (request.getHeader("Content-Type").contains("application/json")) {
return obtainCodeJson(request, jsCode);
}
return request.getParameter(jsCode);
}
public String obtainCodeJson(HttpServletRequest request, String param) {
StringBuilder builder = new StringBuilder();
String line = null;
String code = null;
try{
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
builder.append(line);
}
Map<String, String> map = JsonUtils.fromString(builder.toString(), Map.class, String.class, String.class);
code = map.get(param);
}catch (RuntimeException | IOException e) {
throw new AuthenticationServiceException("獲取參數(shù)失敗");
}
return code;
}
/**
* Provided so that subclasses may configure what is put into the
* authentication request's details property.
*
* @param request that an authentication request is being created for
* @param authRequest the authentication request object that should have its details
* set
*/
protected void setDetails(HttpServletRequest request, JsCodeAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}從上面的代碼可以看出,我們需要定義一個(gè)filter 類繼承 AbstractAuthenticationProcessingFilter 來(lái)獲取前端傳輸?shù)膮?shù)
AbstractAuthenticationProcessingFilter的定義
- AbstractAuthenticationProcessingFilter是Spring Security框架中的一個(gè)過(guò)濾器,用于處理用戶認(rèn)證的相關(guān)操作。
AbstractAuthenticationProcessingFilter的功能有哪些
- 攔截用戶發(fā)起的認(rèn)證請(qǐng)求,并交給AuthenticationManager來(lái)進(jìn)行身份驗(yàn)證。
- 通過(guò)調(diào)用AuthenticationManager完成身份驗(yàn)證后,將認(rèn)證結(jié)果封裝成Authentication對(duì)象。
- 將認(rèn)證結(jié)果傳遞給AbstractAuthenticationProcessingFilter的成功或失敗處理器進(jìn)行處理。
- 處理認(rèn)證成功或失敗的邏輯,例如生成并返回認(rèn)證成功的Jwt token、跳轉(zhuǎn)到特定頁(yè)面、返回錯(cuò)誤信息等。
定義相關(guān)的Provider 類
public class JsCodeAuthenticationProvider implements AuthenticationProvider {
private WxOAuth2Service weChatService;
private UserDetailsService userDetailsService;
private WxMpProperties wxMpProperties;
public JsCodeAuthenticationProvider(WxOAuth2Service weChatService, WxMpProperties wxMpProperties) {
this.weChatService = weChatService;
this.wxMpProperties = wxMpProperties;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
JsCodeAuthenticationToken token = (JsCodeAuthenticationToken) authentication;
String code = (String) token.getPrincipal();
log.info("得到的code:{}", code);
if (StringUtils.isBlank(code)) {
throw new AuthenticationServiceException("jscode 不能為空");
}
WxOAuth2AccessToken wxOAuth2AccessToken;
try {
wxOAuth2AccessToken = weChatService.getAccessToken(wxMpProperties.getAppId(), wxMpProperties.getSecret(), code);
} catch (WxErrorException e) {
throw new AuthenticationServiceException("授權(quán)登錄失敗");
}
WeChatDetailsService weChatDetailsService = (WeChatDetailsService)userDetailsService;
UserDetails details = weChatDetailsService.loadByToken(wxOAuth2AccessToken.getOpenId(), wxOAuth2AccessToken.getAccessToken());
if (details == null) {
throw new AuthenticationServiceException("無(wú)法獲取公眾號(hào)用戶");
}
JsCodeAuthenticationToken authenticationResult = new JsCodeAuthenticationToken(details.getUsername());
authenticationResult.setDetails(token.getDetails());
return authenticationResult;
}
@Override
public boolean supports(Class<?> authentication) {
return JsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
AuthenticationProvider 的定義
AuthenticationProvider是Spring Security框架中的一個(gè)接口,用于身份驗(yàn)證的核心組件。
它的定義如下:
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}它包含兩個(gè)方法:
- authenticate(Authentication authentication):該方法用于執(zhí)行身份驗(yàn)證過(guò)程。輸入?yún)?shù)authentication是一個(gè)封裝了用戶認(rèn)證信息的Authentication對(duì)象,包括用戶名、密碼等信息。該方法返回一個(gè)認(rèn)證成功的Authentication對(duì)象,或者拋出AuthenticationException異常表示認(rèn)證失敗。
- supports(Class<?> authentication):該方法用于判斷是否支持給定類型的認(rèn)證請(qǐng)求。輸入?yún)?shù)authentication是要被驗(yàn)證的對(duì)象類型,通常是UsernamePasswordAuthenticationToken或JwtAuthenticationToken等。該方法返回一個(gè)boolean值,表示是否支持該類型的認(rèn)證請(qǐng)求。
AuthenticationProvider可以自定義實(shí)現(xiàn),用于實(shí)現(xiàn)不同的身份驗(yàn)證邏輯。開發(fā)者可以通過(guò)實(shí)現(xiàn)該接口,并覆蓋其中的方法來(lái)定制化身份驗(yàn)證過(guò)程,例如從數(shù)據(jù)庫(kù)查詢用戶信息并進(jìn)行密碼校驗(yàn)等。
在Spring Security的配置中,可以通過(guò)AuthenticationManagerBuilder來(lái)注冊(cè)和配置AuthenticationProvider的實(shí)例,以供身份驗(yàn)證使用。
定義相關(guān)配置類
@Component
@EnableConfigurationProperties(WxMpProperties.class)
public class JsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationSuccessHandler jsCodeAuthenticationSuccessHandler;
@Autowired
private AuthenticationFailureHandler jsCodeAuthenticationFailureHandler;
@Autowired
private WxOAuth2Service weChatService;
@Autowired
private WechatProperties weChatProperties;
@Autowired
private WxMpProperties wxMpProperties;
@Override
public void configure(HttpSecurity http) throws Exception {
JsCodeAuthenticationFilter mobilePasswordAuthenticationFilter = new JsCodeAuthenticationFilter(weChatProperties);
mobilePasswordAuthenticationFilter.setAuthenticationSuccessHandler(jsCodeAuthenticationSuccessHandler);
mobilePasswordAuthenticationFilter.setAuthenticationFailureHandler(jsCodeAuthenticationFailureHandler);
mobilePasswordAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
JsCodeAuthenticationProvider provider = new JsCodeAuthenticationProvider(weChatService, wxMpProperties);
provider.setUserDetailsService(userDetailsService);
// 將當(dāng)前服務(wù)注冊(cè)到 mobilePasswordAuthenticationFilter 連之后
http.authenticationProvider(provider).addFilterAfter(mobilePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}SecurityConfigurerAdapter 的定義
SecurityConfigurerAdapter是Spring Security提供的一個(gè)抽象類,用于簡(jiǎn)化配置和定制化Spring Security的行為。
它是一個(gè)適配器模式,繼承自SecurityConfigurer接口,并提供了一些默認(rèn)實(shí)現(xiàn)方法,用于提供給開發(fā)者靈活地配置和擴(kuò)展Spring Security。
SecurityConfigurerAdapter的定義如下:
public abstract class SecurityConfigurerAdapter<O extends SecurityFilterChain, B extends SecurityBuilder<O>> implements SecurityConfigurer<O, B> {
// 提供一個(gè)空實(shí)現(xiàn)的configure方法,供子類進(jìn)行覆蓋定制
public void configure(B builder) throws Exception {}
// 提供一個(gè)空實(shí)現(xiàn)的init方法,供子類進(jìn)行覆蓋定制
public void init(B builder) throws Exception {}
// 提供一個(gè)空實(shí)現(xiàn)的configure方法,供子類進(jìn)行覆蓋定制
public void configure(O object) throws Exception {}
// 提供一個(gè)空實(shí)現(xiàn)的postProcess方法,供子類進(jìn)行覆蓋定制
protected void postProcess(O object) throws Exception {}
}開發(fā)者可以繼承SecurityConfigurerAdapter,并重寫其中的方法來(lái)實(shí)現(xiàn)自定義的安全配置。常見的用法是在WebSecurityConfigurerAdapter中繼承SecurityConfigurerAdapter,并重寫configure方法來(lái)配置Spring Security的行為,例如定義認(rèn)證規(guī)則、權(quán)限控制等。通過(guò)繼承SecurityConfigurerAdapter可以避免直接實(shí)現(xiàn)SecurityConfigurer接口時(shí)需要實(shí)現(xiàn)所有方法的繁瑣操作。
整體配置
public void configure(HttpSecurity http) throws Exception {
String[] auth = StringUtils.split( securityProperties.getAuthUrl(), ",");
http.formLogin().failureHandler(authenticationFailureHandler)
.successHandler(authenticationSuccessHandler)
.loginProcessingUrl(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_FORM)
.loginPage(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL)
.and().apply(jsCodeAuthenticationSecurityConfig)
.and().apply(usernameAuthenticationSecurityConfig())
.and().authorizeRequests().antMatchers(auth).authenticated()
.and().authorizeRequests().anyRequest().permitAll()
.and().csrf().disable();
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解使用IntelliJ IDEA新建Java Web后端resfulAPI模板
這篇文章主要介紹了詳解使用IntelliJ IDEA新建Java Web后端resfulAPI模板,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
spring boot異步(Async)任務(wù)調(diào)度實(shí)現(xiàn)方法
在沒(méi)有使用spring boot之前,我們的做法是在配置文件中定義一個(gè)任務(wù)池,然后將@Async注解的任務(wù)丟到任務(wù)池中去執(zhí)行,那么在spring boot中,怎么來(lái)實(shí)現(xiàn)異步任務(wù)的調(diào)用了,下面通過(guò)本文給大家講解,需要的朋友參考下2018-02-02
Swagger @Example與@ExampleProperty使用無(wú)效原因分析
Swagger@Example與@ExampleProperty無(wú)效的原因是Swagger默認(rèn)UI不支持顯示這些配置,即使后端返回的數(shù)據(jù)中有配置的內(nèi)容2026-03-03
Java?Bluetooth?藍(lán)牙通訊?BlueCove?掃描附近的藍(lán)牙設(shè)備(測(cè)試代碼)
BlueCove是一個(gè)開源的藍(lán)牙協(xié)議棧實(shí)現(xiàn),旨在為Java開發(fā)者提供一個(gè)全面的、易于使用的API,從而在應(yīng)用程序中實(shí)現(xiàn)藍(lán)牙功能,該項(xiàng)目支持多種操作系統(tǒng),這篇文章主要介紹了Java?Bluetooth?藍(lán)牙通訊?BlueCove?掃描附近的藍(lán)牙設(shè)備,需要的朋友可以參考下2025-01-01
Spring注解實(shí)現(xiàn)循環(huán)重試功能(適用場(chǎng)景分析)
這篇文章主要介紹了Spring注解實(shí)現(xiàn)循環(huán)重試功能,本篇主要簡(jiǎn)單介紹了Springboot中的Retryable的使用,主要的適用場(chǎng)景和注意事項(xiàng),當(dāng)需要重試的時(shí)候還是很有用的,需要的朋友可以參考下2023-04-04
dubbo如何實(shí)現(xiàn)consumer從多個(gè)group中調(diào)用指定group的provider
這篇文章主要介紹了dubbo如何實(shí)現(xiàn)consumer從多個(gè)group中調(diào)用指定group的provider問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
關(guān)于Mybatis-Plus?Update更新策略問(wèn)題
這篇文章主要介紹了關(guān)于Mybatis-Plus?Update更新策略問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
用Spring將Service注入到Servlet中的流程步驟
在Java Web開發(fā)中,??Servlet??是一個(gè)非常重要的組件,它用于處理客戶端的請(qǐng)求并生成響應(yīng),而?Spring??框架則是一個(gè)廣泛使用的依賴注入框架,可以幫助開發(fā)者管理應(yīng)用中的對(duì)象及其依賴關(guān)系,本文將介紹如何使用Spring框架將Service層的對(duì)象注入到Servlet中2025-01-01

