最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringSecurity 自定義認(rèn)證登錄的項(xiàng)目實(shí)踐

 更新時(shí)間:2024年08月18日 10:16:14   作者:way_more  
本文主要介紹了SpringSecurity 自定義認(rèn)證登錄的項(xiàng)目實(shí)踐,以手機(jī)驗(yàn)證碼登錄為例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

現(xiàn)在登錄方式越來(lái)越多,傳統(tǒng)的賬號(hào)密碼登錄已經(jīng)不能滿足我們的需求??赡芪覀冞€需要手機(jī)驗(yàn)證碼登錄,郵箱驗(yàn)證碼登錄,一鍵登錄等。這時(shí)候就需要我們自定義我們系統(tǒng)的認(rèn)證登錄流程,下面,我就一步一步在SpringSecurity 自定義認(rèn)證登錄,以手機(jī)驗(yàn)證碼登錄為例

1-自定義用戶對(duì)象

Spring Security 中定義了 UserDetails 接口來(lái)規(guī)范開(kāi)發(fā)者自定義的用戶對(duì)象,我們自定義對(duì)象直接實(shí)現(xiàn)這個(gè)接口,然后定義自己的對(duì)象屬性即可

/**
 * 自定義用戶角色
 */
@Data
public class PhoneUserDetails implements UserDetails {

    public static final String ACCOUNT_ACTIVE_STATUS = "ACTIVE";

    public static final Integer NOT_EXPIRED = 0;

    private String userId;
    private String userName;
    private String phone;
    private String status;
    private Integer isExpired;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collection = new HashSet<>();
        return collection;
    }

    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return this.phone;
    }

    @Override
    public boolean isAccountNonExpired() {
        return NOT_EXPIRED.equals(isExpired);
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return ACCOUNT_ACTIVE_STATUS.equals(status);
    }
}

自定義角色實(shí)現(xiàn)UserDetails接口方法時(shí),根據(jù)自己的需要來(lái)實(shí)現(xiàn)

2-自定義UserDetailsService

UserDetails是用來(lái)規(guī)范我們自定義用戶對(duì)象,而負(fù)責(zé)提供用戶數(shù)據(jù)源的接口是UserDetailsService,它提供了一個(gè)查詢用戶的方法,我們需要實(shí)現(xiàn)它來(lái)查詢用戶

@Service
public class PhoneUserDetailsService implements UserDetailsService {

    public static final String USER_INFO_SUFFIX = "user:info:";

    @Autowired
    private PhoneUserMapper phoneUserMapper;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    /**
     * 查找用戶
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //先查詢緩存
        String userKey = USER_INFO_SUFFIX + username;
        PhoneUserDetails cacheUserInfo = (PhoneUserDetails) redisTemplate.opsForValue().get(userKey);
        if (cacheUserInfo == null){
            //緩存不存在,從數(shù)據(jù)庫(kù)查找用戶信息
            PhoneUserDetails phoneUserDetails = phoneUserMapper.selectPhoneUserByPhone(username);
            if (phoneUserDetails == null){
                throw new UsernameNotFoundException("用戶不存在");
            }
            //加入緩存
            redisTemplate.opsForValue().set(userKey,phoneUserDetails);
            return phoneUserDetails;
        }
        return cacheUserInfo;
    }

}

3-自定義Authentication

在SpringSecurity認(rèn)證過(guò)程中,最核心的對(duì)象為Authentication,這個(gè)對(duì)象用于在認(rèn)證過(guò)程中存儲(chǔ)主體的各種基本信息(例如:用戶名,密碼等等)和主體的權(quán)限信息(例如,接口權(quán)限)。

我們可以通過(guò)繼承AbstractAuthenticationToken來(lái)自定義的Authentication對(duì)象,我們參考SpringSecurity自有的UsernamePasswordAuthenticationToken來(lái)實(shí)現(xiàn)自己的AbstractAuthenticationToken 實(shí)現(xiàn)類

@Getter
@Setter
public class PhoneAuthenticationToken  extends AbstractAuthenticationToken {

    private final Object principal;

    private Object credentials;

   /**
     * 可以自定義屬性
     */
    private String phone;

    /**
     * 創(chuàng)建一個(gè)未認(rèn)證的對(duì)象
     * @param principal
     * @param credentials
     */
    public PhoneAuthenticationToken(Object principal, Object credentials) {
        super(null);
        this.principal = principal;
        this.credentials = credentials;
        setAuthenticated(false);
    }

    public PhoneAuthenticationToken(Collection<? extends GrantedAuthority> authorities, Object principal, Object credentials) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        // 必須使用super,因?yàn)槲覀円貙?xiě)
        super.setAuthenticated(true);
    }

    /**
     * 不能暴露Authenticated的設(shè)置方法,防止直接設(shè)置
     * @param isAuthenticated
     * @throws IllegalArgumentException
     */
    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        Assert.isTrue(!isAuthenticated,
                "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        super.setAuthenticated(false);
    }

    /**
     * 用戶憑證,如密碼
     * @return
     */
    @Override
    public Object getCredentials() {
        return credentials;
    }

    /**
     * 被認(rèn)證主體的身份,如果是用戶名/密碼登錄,就是用戶名
     * @return
     */
    @Override
    public Object getPrincipal() {
        return principal;
    }
}

因?yàn)槲覀兊尿?yàn)證碼是有時(shí)效性的,所以eraseCredentials 方法也沒(méi)必要重寫(xiě)了,無(wú)需擦除。主要是設(shè)置Authenticated屬性,Authenticated屬性代表是否已認(rèn)證

4-自定義AuthenticationProvider

AuthenticationProvider對(duì)于Spring Security來(lái)說(shuō)相當(dāng)于是身份驗(yàn)證的入口。通過(guò)向AuthenticationProvider提供認(rèn)證請(qǐng)求,我們可以得到認(rèn)證結(jié)果,進(jìn)而提供其他權(quán)限控制服務(wù)。

在Spring Security中,AuthenticationProvider是一個(gè)接口,其實(shí)現(xiàn)類需要覆蓋authenticate(Authentication authentication)方法。當(dāng)用戶請(qǐng)求認(rèn)證時(shí),Authentication Provider就會(huì)嘗試對(duì)用戶提供的信息(Authentication對(duì)象里的信息)進(jìn)行認(rèn)證評(píng)估,并返回Authentication對(duì)象。通常一個(gè)provider對(duì)應(yīng)一種認(rèn)證方式,ProviderManager中可以包含多個(gè)AuthenticationProvider表示系統(tǒng)可以支持多種認(rèn)證方式。

Spring Security定義了AuthenticationProvider 接口來(lái)規(guī)范我們的AuthenticationProvider 實(shí)現(xiàn)類,AuthenticationProvider 接口只有兩個(gè)方法,源碼如下

public interface AuthenticationProvider {
	
	//身份認(rèn)證
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;

	//是否支持傳入authentication類型的認(rèn)證
	boolean supports(Class<?> authentication);
}

下面自定義我們的AuthenticationProvider,如果AuthenticationProvider認(rèn)證成功,它會(huì)返回一個(gè)完全有效的Authentication對(duì)象,其中authenticated屬性為true,已授權(quán)的權(quán)限列表(GrantedAuthority列表),以及用戶憑證。

/**
 * 手機(jī)驗(yàn)證碼認(rèn)證授權(quán)提供者
 */
@Data
public class PhoneAuthenticationProvider  implements AuthenticationProvider {

    private RedisTemplate<String,Object> redisTemplate;

    private PhoneUserDetailsService phoneUserDetailsService;

    public static final String PHONE_CODE_SUFFIX = "phone:code:";

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        //先將authentication轉(zhuǎn)為我們自定義的Authentication對(duì)象
        PhoneAuthenticationToken authenticationToken = (PhoneAuthenticationToken) authentication;
        //校驗(yàn)參數(shù)
        Object principal = authentication.getPrincipal();
        Object credentials = authentication.getCredentials();
        if (principal == null || "".equals(principal.toString()) || credentials == null || "".equals(credentials.toString())){
            throw new InternalAuthenticationServiceException("手機(jī)/手機(jī)驗(yàn)證碼為空!");
        }
        //獲取手機(jī)號(hào)和驗(yàn)證碼
        String phone = (String) authenticationToken.getPrincipal();
        String code = (String) authenticationToken.getCredentials();
        //查找手機(jī)用戶信息,驗(yàn)證用戶是否存在
        UserDetails userDetails = phoneUserDetailsService.loadUserByUsername(phone);
        if (userDetails == null){
            throw new InternalAuthenticationServiceException("用戶手機(jī)不存在!");
        }
        String codeKey =  PHONE_CODE_SUFFIX+phone;
        //手機(jī)用戶存在,驗(yàn)證手機(jī)驗(yàn)證碼是否正確
        if (!redisTemplate.hasKey(codeKey)){
            throw new InternalAuthenticationServiceException("驗(yàn)證碼不存在或已失效!");
        }
        String realCode = (String) redisTemplate.opsForValue().get(codeKey);
        if (StringUtils.isBlank(realCode) || !realCode.equals(code)){
            throw new InternalAuthenticationServiceException("驗(yàn)證碼錯(cuò)誤!");
        }
        //返回認(rèn)證成功的對(duì)象
        PhoneAuthenticationToken phoneAuthenticationToken = new PhoneAuthenticationToken(userDetails.getAuthorities(),phone,code);
        phoneAuthenticationToken.setPhone(phone);
        //details是一個(gè)泛型屬性,用于存儲(chǔ)關(guān)于認(rèn)證令牌的額外信息。其類型是 Object,所以你可以存儲(chǔ)任何類型的數(shù)據(jù)。這個(gè)屬性通常用于存儲(chǔ)與認(rèn)證相關(guān)的詳細(xì)信息,比如用戶的角色、IP地址、時(shí)間戳等。
        phoneAuthenticationToken.setDetails(userDetails);
        return phoneAuthenticationToken;
    }


    /**
     * ProviderManager 選擇具體Provider時(shí)根據(jù)此方法判斷
     * 判斷 authentication 是不是 SmsCodeAuthenticationToken 的子類或子接口
     */
    @Override
    public boolean supports(Class<?> authentication) {
        //isAssignableFrom方法如果比較類和被比較類類型相同,或者是其子類、實(shí)現(xiàn)類,返回true
        return PhoneAuthenticationToken.class.isAssignableFrom(authentication);
    }

}

5-自定義AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter是Spring Security中的一個(gè)重要的過(guò)濾器,用于處理用戶的身份驗(yàn)證。它是一個(gè)抽象類,提供了一些基本的身份驗(yàn)證功能,可以被子類繼承和擴(kuò)展。該過(guò)濾器的主要作用是從請(qǐng)求中獲取用戶的身份認(rèn)證信息,并將其傳遞給AuthenticationManager進(jìn)行身份驗(yàn)證。如果身份驗(yàn)證成功,它將生成一個(gè)身份驗(yàn)證令牌,并將其傳遞給AuthenticationSuccessHandler進(jìn)行處理。如果身份驗(yàn)證失敗,它將生成一個(gè)身份驗(yàn)證異常,并將其傳遞給AuthenticationFailureHandler進(jìn)行處理。AbstractAuthenticationProcessingFilter還提供了一些其他的方法,如setAuthenticationManager()、setAuthenticationSuccessHandler()、setAuthenticationFailureHandler()等,可以用于定制身份認(rèn)證的處理方式。

我們需要自定義認(rèn)證流程,那么就需要繼承AbstractAuthenticationProcessingFilter這個(gè)抽象類

Spring Security 的UsernamePasswordAuthenticationFilter也是繼承了AbstractAuthenticationProcessingFilter,我們可以參考實(shí)現(xiàn)自己的身份驗(yàn)證

public class PhoneVerificationCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    /**
     * 參數(shù)名稱
     */
    public static final String USER_PHONE = "phone";
    public static final String PHONE_CODE = "phoneCode";

    private String userPhoneParameter = USER_PHONE;
    private String phoneCodeParameter = PHONE_CODE;

    /**
     * 是否只支持post請(qǐng)求
     */
    private boolean postOnly = true;

    /**
     * 通過(guò)構(gòu)造函數(shù),設(shè)置對(duì)哪些請(qǐng)求進(jìn)行過(guò)濾,如下設(shè)置,則只有接口為 /phone_login,請(qǐng)求方式為 POST的請(qǐng)求才會(huì)進(jìn)入邏輯
     */
    public PhoneVerificationCodeAuthenticationFilter(){
        super(new RegexRequestMatcher("/phone_login","POST"));
    }


    /**
     * 認(rèn)證方法
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        PhoneAuthenticationToken phoneAuthenticationToken;
        //請(qǐng)求方法類型校驗(yàn)
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        //如果不是json參數(shù),從request獲取參數(shù)
        if (!request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE) && !request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
            String userPhone = request.getParameter(userPhoneParameter);
            String phoneCode = request.getParameter(phoneCodeParameter);
            phoneAuthenticationToken = new PhoneAuthenticationToken(userPhone,phoneCode);
        }else {
            //如果是json請(qǐng)求使用取參數(shù)邏輯,直接用map接收,也可以創(chuàng)建一個(gè)實(shí)體類接收
            Map<String, String> loginData = new HashMap<>(2);
            try {
                loginData = JSONObject.parseObject(request.getInputStream(), Map.class);
            } catch (IOException e) {
                throw new InternalAuthenticationServiceException("請(qǐng)求參數(shù)異常");
            }
            // 獲得請(qǐng)求參數(shù)
            String userPhone = loginData.get(userPhoneParameter);
            String phoneCode = loginData.get(phoneCodeParameter);
            phoneAuthenticationToken = new PhoneAuthenticationToken(userPhone,phoneCode);
        }
        phoneAuthenticationToken.setDetails(authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(phoneAuthenticationToken);
    }


}

6-自定義認(rèn)證成功和失敗的處理類

pringSecurity處理成功和失敗一般是進(jìn)行頁(yè)面跳轉(zhuǎn),但是在前后端分離的架構(gòu)下,前后端的交互一般是通過(guò)json進(jìn)行交互,不需要后端重定向或者跳轉(zhuǎn),只需要返回我們的登陸信息即可。

這就要實(shí)現(xiàn)我們的認(rèn)證成功和失敗處理類

認(rèn)證成功接口:AuthenticationSuccessHandler,只有一個(gè)onAuthenticationSuccess認(rèn)證成功處理方法

認(rèn)證失敗接口:AuthenticationFailureHandler,只有一個(gè)onAuthenticationFailure認(rèn)證失敗處理方法

我們實(shí)現(xiàn)相應(yīng)接口,在方法中定義好我們的處理邏輯即可

@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    /**
     * 登錄成功處理
     * @param httpServletRequest
     * @param httpServletResponse
     * @param authentication
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=utf-8");
        Map<String, Object> resp = new HashMap<>();
        resp.put("status", 200);
        resp.put("msg", "登錄成功!");
        resp.put("token", new UUIDGenerator().next());
        String s = JSONObject.toJSONString(resp);
        httpServletResponse.getWriter().write(s);
    }

}

@Slf4j
@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {

    /**
     * 登錄失敗處理
     * @param httpServletRequest
     * @param httpServletResponse
     * @param exception
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException exception) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=utf-8");
        Map<String, Object> resp = new HashMap<>();
        resp.put("status", 500);
        resp.put("msg", "登錄失敗!" );
        String s  = JSONObject.toJSONString(resp);
        log.error("登錄異常:",exception);
        httpServletResponse.getWriter().write(s);
    }


}

7-修改配置類

想要應(yīng)用自定義的 AuthenticationProvider 和 AbstractAuthenticationProcessingFilter,還需在WebSecurityConfigurerAdapter 配置類進(jìn)行配置。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private PhoneUserDetailsService phoneUserDetailsService;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin().successHandler(new CustomAuthenticationSuccessHandler()).permitAll()
                .and()
                .csrf().disable();

        //添加自定義過(guò)濾器
        PhoneVerificationCodeAuthenticationFilter phoneVerificationCodeAuthenticationFilter = new PhoneVerificationCodeAuthenticationFilter();
        //設(shè)置過(guò)濾器認(rèn)證成功和失敗的處理類
        phoneVerificationCodeAuthenticationFilter.setAuthenticationSuccessHandler(new CustomAuthenticationSuccessHandler());
        phoneVerificationCodeAuthenticationFilter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler());
        //設(shè)置認(rèn)證管理器
        phoneVerificationCodeAuthenticationFilter.setAuthenticationManager(authenticationManager());
        //addFilterBefore方法用于將自定義的過(guò)濾器添加到過(guò)濾器鏈中,并指定該過(guò)濾器在哪個(gè)已存在的過(guò)濾器之前執(zhí)行
        http.addFilterBefore(phoneVerificationCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        // 采用密碼授權(quán)模式需要顯式配置AuthenticationManager
        return super.authenticationManagerBean();
    }

    /**
     *
     * @param auth 認(rèn)證管理器
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //添加自定義認(rèn)證提供者
        auth.authenticationProvider(phoneAuthenticationProvider());
    }

    /**
     * 手機(jī)驗(yàn)證碼登錄的認(rèn)證提供者
     * @return
     */
    @Bean
    public PhoneAuthenticationProvider phoneAuthenticationProvider(){
        PhoneAuthenticationProvider phoneAuthenticationProvider = new PhoneAuthenticationProvider();
        phoneAuthenticationProvider.setRedisTemplate(redisTemplate);
        phoneAuthenticationProvider.setPhoneUserDetailsService(phoneUserDetailsService);
        return phoneAuthenticationProvider;
    }

}

在Spring Security框架中,addFilterBefore方法用于將自定義的過(guò)濾器添加到過(guò)濾器鏈中,并指定該過(guò)濾器在哪個(gè)已存在的過(guò)濾器之前執(zhí)行。還有一個(gè)addFilterAfter方法可以將自定義過(guò)濾器添加到指定過(guò)濾器之后執(zhí)行。

8-測(cè)試

完成上面的操作之后,我們就可以測(cè)試下新的登錄方式是否生效了。我這里直接使用postman進(jìn)行登錄請(qǐng)求

在這里插入圖片描述

到此這篇關(guān)于SpringSecurity 自定義認(rèn)證登錄的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)SpringSecurity 自定義認(rèn)證登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • Java實(shí)現(xiàn)的Base64加密算法示例

    Java實(shí)現(xiàn)的Base64加密算法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的Base64加密算法,結(jié)合實(shí)例形式分析了Java實(shí)現(xiàn)的base64編碼轉(zhuǎn)換相關(guān)使用方法及操作注意事項(xiàng),需要的朋友可以參考下
    2018-04-04
  • 詳解springboot 使用c3p0數(shù)據(jù)庫(kù)連接池的方法

    詳解springboot 使用c3p0數(shù)據(jù)庫(kù)連接池的方法

    本篇文章主要介紹了springboot 使用c3p0數(shù)據(jù)庫(kù)連接池的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Java中Integer類型值相等判斷方法

    Java中Integer類型值相等判斷方法

    這篇文章主要給大家介紹了關(guān)于Java中Integer類型值相等判斷的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • springboot 啟動(dòng)如何修改application.properties的參數(shù)

    springboot 啟動(dòng)如何修改application.properties的參數(shù)

    這篇文章主要介紹了springboot 啟動(dòng)如何修改application.properties的參數(shù)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Spring Cloud Gateway 使用JWT工具類做用戶登錄校驗(yàn)功能

    Spring Cloud Gateway 使用JWT工具類做用戶登錄校驗(yàn)功能

    這篇文章主要介紹了Spring Cloud Gateway 使用JWT工具類做用戶登錄校驗(yàn)的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • 詳解Java實(shí)現(xiàn)JSONArray轉(zhuǎn)Map的三種實(shí)現(xiàn)方式

    詳解Java實(shí)現(xiàn)JSONArray轉(zhuǎn)Map的三種實(shí)現(xiàn)方式

    本文主要介紹了Java實(shí)現(xiàn)JSONArray轉(zhuǎn)Map的三種實(shí)現(xiàn)方式,本文只是自己常用的三種,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Mybatis通過(guò)Mapper代理連接數(shù)據(jù)庫(kù)的方法

    Mybatis通過(guò)Mapper代理連接數(shù)據(jù)庫(kù)的方法

    這篇文章主要介紹了Mybatis通過(guò)Mapper代理連接數(shù)據(jù)庫(kù)的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • 詳解Java集合類之List篇

    詳解Java集合類之List篇

    這篇文章主要為大家詳細(xì)介紹一下Java集合類中List的用法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定幫助,感興趣的可以了解一下
    2022-07-07
  • 基于rocketmq的有序消費(fèi)模式和并發(fā)消費(fèi)模式的區(qū)別說(shuō)明

    基于rocketmq的有序消費(fèi)模式和并發(fā)消費(fèi)模式的區(qū)別說(shuō)明

    這篇文章主要介紹了基于rocketmq的有序消費(fèi)模式和并發(fā)消費(fèi)模式的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • springboot開(kāi)啟Bean數(shù)據(jù)校驗(yàn)功能

    springboot開(kāi)啟Bean數(shù)據(jù)校驗(yàn)功能

    這篇文章主要介紹了springboot開(kāi)啟Bean數(shù)據(jù)校驗(yàn)功能,通過(guò)啟用Bean屬性校驗(yàn)導(dǎo)入JSR303與Hibernate校驗(yàn)框架坐標(biāo),使用@Validated注解啟用校驗(yàn)功能,需要的朋友可以參考下
    2023-10-10

最新評(píng)論

偃师市| 东乡族自治县| 新兴县| 荃湾区| 东安县| 保亭| 高阳县| 武清区| 巴里| 镶黄旗| 昌黎县| 绍兴县| 成安县| 天水市| 张北县| 独山县| 南阳市| 呼伦贝尔市| 兰西县| 平凉市| 夏津县| 上饶市| 南宫市| 安岳县| 方正县| 德格县| 浙江省| 弥勒县| 渭南市| 饶平县| 广昌县| 嵩明县| 古交市| 惠来县| 乌鲁木齐县| 淅川县| 井陉县| 东阳市| 龙州县| 三明市| 衡南县|