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

SpringSecurity集成第三方登錄過程詳解(最新推薦)

 更新時(shí)間:2024年05月13日 11:41:14   作者:小???王八  
在ThirdAuthenticationFilter 類的attemptAuthentication()方法中,我們通過authType類型,然后創(chuàng)建對(duì)應(yīng)的Authentication實(shí)現(xiàn)來實(shí)現(xiàn)不同方式的登錄,下面給大家分享SpringSecurity集成第三方登錄過程,感興趣的朋友一起看看吧

SpringSecurity 集成第三方登錄

認(rèn)證及自定義流程

首先我們提供一個(gè)實(shí)現(xiàn)了AbstractAuthenticationProcessingFilter抽象類的過濾器,用來代替UsernamePasswordAuthenticationFilter邏輯,然后提供一個(gè)AuthenticationProvider實(shí)現(xiàn)類代替AbstractUserDetailsAuthenticationProvider或DaoAuthenticationProvider,最后再提供一個(gè)UserDetailsService實(shí)現(xiàn)類。

1.驗(yàn)證碼登錄

1.通用過濾器實(shí)現(xiàn)–ThirdAuthenticationFilter

這個(gè)ThirdAuthenticationFilter過濾器我們可以仿照UsernamePasswordAuthenticationFilter來實(shí)現(xiàn)(也實(shí)現(xiàn)了AbstractAuthenticationProcessingFilter抽象類),主要是重新定義了attemptAuthentication()方法,這里需要根據(jù)“authType”參數(shù)值的類別構(gòu)建不同的AbstractAuthenticationToken,具體實(shí)現(xiàn)如下:

    //驗(yàn)證類型,比如Sms,uernamepassword等
    private String authTypeParameter = "authType";
    //對(duì)應(yīng)用戶名或手機(jī)號(hào)等
    private String principalParameter = "principal";
    //對(duì)應(yīng)密碼或驗(yàn)證碼等
    private String credentialsParameter = "credentials";
    private boolean postOnly = true;
    public ThirdAuthenticationFilter() {
        super(new AntPathRequestMatcher("/login/doLogin", "POST"));
    }
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        String authType = request.getParameter(authTypeParameter);
        if(StringUtils.isEmpty(authType)){
            authType = AuthTypeEnum.AUTH_TYPE_DEFAULT.getAuthType();
        }
        String principal = request.getParameter(principalParameter);
        String credentials = request.getParameter(credentialsParameter);
        AbstractAuthenticationToken authRequest = null;
        switch (authType){
            case "sms":
                authRequest = new SmsAuthenticationToken(principal, credentials);
                ((SmsAuthenticationToken)authRequest).setCode((String)request.getSession().getAttribute("code"));
                break;
            case "github":
                authRequest = new GithubAuthenticationToken(principal, credentials);
                break;
            case "default":
                authRequest = new UsernamePasswordAuthenticationToken(principal, credentials);
        }
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

定義了ThirdAuthenticationSecurityConfig 配置類,我們還需要在SpringSecurity配置類中應(yīng)用才能生效,具體實(shí)現(xiàn)如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/error","/login/**","/login/goLogin","/login/doLogin","/login/code","/login/authorization_code").anonymous()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login/goLogin")
            .loginProcessingUrl("/login/doLogin")
            .failureUrl("/login/error")
            .permitAll()
            .successHandler(new QriverAuthenticationSuccessHandler("/index/toIndex"));
	//這里我們省略了一些配置 ……
	//應(yīng)用前面定義的配置
    http.apply(thirdAuthenticationSecurityConfig);
}

至此,我們定義的通用第三方過濾器就完成了,并且也完成了在SpringSecurity中生效的配置。下面我們就開始分別實(shí)現(xiàn)不同類型登錄的具體過程。

在ThirdAuthenticationFilter 類的attemptAuthentication()方法中,我們通過authType類型,然后創(chuàng)建對(duì)應(yīng)的Authentication實(shí)現(xiàn)來實(shí)現(xiàn)不同方式的登錄,這里我們主要實(shí)現(xiàn)了如下三種方式,我們分別梳理一下。

3、默認(rèn)的登錄過程

  默認(rèn)的登錄過程,即根據(jù)用戶名密碼進(jìn)行登錄,需要使用到UsernamePasswordAuthenticationToken,當(dāng)“authType”參數(shù)為"default"時(shí),這里就會(huì)創(chuàng)建UsernamePasswordAuthenticationToken對(duì)象,然后后續(xù)通過ProviderManager的authenticate()方法,最后就會(huì)調(diào)用AbstractUserDetailsAuthenticationProvider(DaoAuthenticationProvider)的 authenticate()方法,最終又會(huì)調(diào)用定義的UserDetailsService實(shí)現(xiàn)類。這是默認(rèn)的過程,這里就不再重復(fù)其中的邏輯,除了UserDetailsService實(shí)現(xiàn)類需要自己定義,其他都是SpringSecurity提供的實(shí)現(xiàn)類。

4、短信驗(yàn)證碼登錄實(shí)現(xiàn)

  短信驗(yàn)證碼登錄,是最貼近用戶名密碼登錄的一種方式,所以我們完全可以仿照用戶名密碼這種方式實(shí)現(xiàn)。我們這里先梳理一下短信驗(yàn)證碼登錄的業(yè)務(wù)邏輯:首先,登錄界面輸入手機(jī)號(hào)碼,然后再點(diǎn)擊“獲取驗(yàn)證碼”按鈕獲取短信驗(yàn)證碼,然后輸入收到的短信驗(yàn)證碼,最后點(diǎn)擊“登錄”按鈕進(jìn)行登錄認(rèn)證。和用戶名密碼登錄相比,短信驗(yàn)證碼登錄多了一個(gè)獲取驗(yàn)證碼的過程,其他其實(shí)都是一樣的,我們下面逐步實(shí)現(xiàn)短信驗(yàn)證碼登錄:

@RestController
@RequestMapping("/login")
public class SmsValidateCodeController {
	//生成驗(yàn)證碼的實(shí)例對(duì)象
    @Autowired
    private ValidateCodeGenerator smsCodeGenerator;
    //調(diào)用服務(wù)商接口,發(fā)送短信驗(yàn)證碼的實(shí)例對(duì)象
    @Autowired
    private DefaultSmsCodeSender defaultSmsCodeSender;
    @RequestMapping("/code")
    public String createSmsCode(HttpServletRequest request, HttpServletResponse response) throws ServletRequestBindingException {
        ValidateCode smsCode = smsCodeGenerator.generate(new ServletWebRequest(request));
        String mobile = (String)request.getParameter("principal");
        request.getSession().setAttribute("code",smsCode.getCode());
        defaultSmsCodeSender.send(mobile, smsCode.getCode());
        System.out.println("驗(yàn)證碼:" + smsCode.getCode());
        return "驗(yàn)證碼發(fā)送成功!";
    }
}

在上述方法中,我們注入了smsCodeGenerator和defaultSmsCodeSender兩個(gè)實(shí)例對(duì)象,分別用來生成驗(yàn)證碼和發(fā)送短信驗(yàn)證碼,這個(gè)可以根據(jù)項(xiàng)目的實(shí)際情況進(jìn)行定義和實(shí)現(xiàn),這里不再貼出其中的實(shí)現(xiàn)。同時(shí)在createSmsCode()方法中,還有一點(diǎn)需要注意的就是,我們發(fā)出去的短信驗(yàn)證碼需要進(jìn)行保存,方便后續(xù)登錄時(shí)進(jìn)行驗(yàn)證,這個(gè)也可以選擇很多方法,比如說會(huì)話、數(shù)據(jù)庫(kù)、緩存等,我這里為了簡(jiǎn)單,直接存到了session會(huì)話中了。

然后,我們前面定義ThirdAuthenticationFilter過濾器時(shí),根據(jù)登錄方式不同,需要對(duì)應(yīng)的Authentication對(duì)象,這里我們還需要?jiǎng)?chuàng)建短信驗(yàn)證登錄需要的Authentication類,這里我們可以仿照UsernamePasswordAuthenticationToken類進(jìn)行編寫,實(shí)現(xiàn)如下

public class SmsAuthenticationToken  extends AbstractAuthenticationToken {
    //對(duì)應(yīng)手機(jī)號(hào)碼
    private final Object principal;
    //對(duì)應(yīng)手機(jī)驗(yàn)證碼
    private Object credentials;
    //后臺(tái)存儲(chǔ)的短信驗(yàn)證碼,用于驗(yàn)證前端傳過來的是否正確
    private String code;
    public SmsAuthenticationToken(String mobile, Object credentials){
        super(null);
        this.principal = mobile;
        this.credentials = credentials;
        this.code = code;
        setAuthenticated(false);
    }
    public SmsAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities, Object credentials){
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }
    @Override
    public Object getCredentials() {
        return this.credentials;
    }
    @Override
    public Object getPrincipal() {
        return this.principal;
    }
    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);
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
        credentials = null;
    }
}

在SmsAuthenticationToken 類中,我們?cè)黾恿艘粋€(gè)code屬性,其實(shí)該屬性不是必須的,我這里是為了方便傳遞存儲(chǔ)在session會(huì)話中的驗(yàn)證碼而添加的,如果使用緩存或數(shù)據(jù)庫(kù)進(jìn)行存儲(chǔ)驗(yàn)證碼,該屬性就可以省略。

在AuthenticationManager的authenticate()方法中,會(huì)根據(jù)Authentication類型選擇AuthenticationProvider對(duì)象,所以我們這里自定義短信驗(yàn)證碼需要的AuthenticationProvider對(duì)象,實(shí)現(xiàn)如下:

@Component
public class SmsAuthenticationProvider implements AuthenticationProvider{
    @Autowired
    @Qualifier("smsUserDetailsService")
    private UserDetailsService userDetailsService;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsAuthenticationToken token = (SmsAuthenticationToken) authentication;
        String mobile = (String)token.getPrincipal();
        //首先,驗(yàn)證驗(yàn)證碼是否正確
        String code = (String)token.getCredentials();
        String sCode = token.getCode();
        if(StringUtils.isEmpty(code) || !code.equalsIgnoreCase(sCode)){
            throw new BadCredentialsException("手機(jī)驗(yàn)證碼錯(cuò)誤(Bad credentials),請(qǐng)重試!");
        }
        //然后,查詢對(duì)應(yīng)用戶
        UserDetails user = userDetailsService.loadUserByUsername(mobile);
        if (Objects.isNull(user)) {
            throw new InternalAuthenticationServiceException("根據(jù)手機(jī)號(hào):" + mobile + ",無法獲取對(duì)應(yīng)的用戶信息!");
        }
        SmsAuthenticationToken authenticationResult = new SmsAuthenticationToken(user.getUsername(), user.getAuthorities(), token.getCredentials());
        authenticationResult.setDetails(token.getDetails());
        return authenticationResult;
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return SmsAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

在SmsAuthenticationProvider 中,supports()方法決定了該實(shí)例對(duì)象僅支持SmsAuthenticationToken對(duì)象的驗(yàn)證。同時(shí),根據(jù)authenticate()方法傳遞參數(shù)authentication對(duì)象(包括了登錄信息:手機(jī)號(hào)和驗(yàn)證碼,session存儲(chǔ)的驗(yàn)證碼),我們這里session存儲(chǔ)的驗(yàn)證碼,是因?yàn)槲覀儾捎昧藭?huì)話存儲(chǔ)的方式,如果使用數(shù)據(jù)庫(kù),我們這里就可以通過手機(jī)號(hào),去數(shù)據(jù)庫(kù)或緩存查詢對(duì)應(yīng)的驗(yàn)證碼,然后和authentication對(duì)象傳遞過來的驗(yàn)證碼進(jìn)行比對(duì),驗(yàn)證成功,說明登錄認(rèn)證成功,否則登錄認(rèn)證失敗。登錄成功后,我們就可以調(diào)用userDetailsService對(duì)象的loadUserByUsername()方法獲取登錄用戶的其他相關(guān)信息(權(quán)限等),具體實(shí)現(xiàn)在自定義的SmsUserDetailsService類中實(shí)現(xiàn),具體如下:

@Component("smsUserDetailsService")
public class SmsUserDetailsService implements UserDetailsService {
    private Logger logger = LoggerFactory.getLogger(SmsUserDetailsService.class);
    @Autowired
    private SysUserService sysUserService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1、查詢用戶信息
        SysUser user = new SysUser();
        user.setMobile(username);
        SysUser qUser = sysUserService.getOne(new QueryWrapper<>(user),true);
        if(qUser == null) {
            logger.info("手機(jī)號(hào)為”" + username + "“的用戶不存在?。?!");
            throw new UsernameNotFoundException("手機(jī)號(hào)為”" + username + "“的用戶不存在?。?!");
        }
        //2、封裝用戶角色
        UserRole userRole = sysUserService.getRoleByUserId(qUser.getId());
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(String.valueOf(userRole.getRoleId())));
        return new LoginUser(qUser.getUsername(), qUser.getPassword(),authorities);
    } 
}

2.GitHub登錄

和短信驗(yàn)證碼登錄認(rèn)證相比,Github登錄又會(huì)有自己的特殊性,我們這里先梳理一下基于Github進(jìn)行登錄驗(yàn)證的大致邏輯:首先,點(diǎn)擊Github登錄認(rèn)證按鈕,然后會(huì)跳轉(zhuǎn)到github登錄界面,輸入github系統(tǒng)的用戶名密碼,登錄成功,就會(huì)跳轉(zhuǎn)到我們自己的系統(tǒng)中的首頁(yè)。和基于用戶名密碼的登錄方式相比,Github登錄不需要類似用戶名和密碼這樣的輸入(在自己的系統(tǒng)中),同時(shí)又需要根據(jù)獲取到的github用戶信息,換取在自己系統(tǒng)對(duì)應(yīng)的用戶信息。具體實(shí)現(xiàn)步驟如下:

在github的配置省略

@Controller
@RequestMapping("/login")
public class GithubValidateController {
    @Autowired
    private GithubClientService githubClientService;
    @RequestMapping("/authorization_code")
    public void authorization_code(HttpServletRequest request, HttpServletResponse response, String code) throws ServletRequestBindingException, IOException {
        //github登錄驗(yàn)證,并獲取access_token
        Map<String,String> resp = githubClientService.queryAccessToken(code);
        //跳轉(zhuǎn)本系統(tǒng)的登錄流程,獲取用戶信息,實(shí)現(xiàn)兩個(gè)系統(tǒng)用戶的對(duì)接
        String url = "http://localhost:8888/qriver-admin/login/doLogin";
        this.sendByPost(response, url,resp.get("access_token"),"github");
        //this.sendByPost(response, url,"access_token","github");
    }
    public void sendByPost(HttpServletResponse response,String url, String principal, String authType) throws IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        out.println("<HTML>");
        out.println(" <HEAD><TITLE>Post 方法</TITLE></HEAD>");
        out.println(" <BODY>");
        out.println("<form name=\"submitForm\" action=\"" + url + "\" method=\"post\">");
        out.println("<input type=\"hidden\" name=\"principal\" value=\"" + principal + "\"/>");
        out.println("<input type=\"hidden\" name=\"authType\" value=\"" + authType + "\"/>");
        out.println("</from>");
        out.println("<script>window.document.submitForm.submit();</script> ");
        out.println(" </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }
}

“/login/authorization_code”接口對(duì)應(yīng)了我們?cè)贕ithub中配置的回調(diào)函數(shù),即在Github登錄驗(yàn)證成功后,就會(huì)回調(diào)該接口,我們就是就在回調(diào)方法中,模擬了用戶名密碼登錄的方式,調(diào)用了SpringSecurity登錄認(rèn)證需要的“/login/doLogin”接口。這里,我們通過queryAccessToken()方法根據(jù)回調(diào)傳遞的code獲取對(duì)應(yīng)的accessToken,然后把a(bǔ)ccessToken作為登錄使用的principal 參數(shù)值,之而立不需要傳遞密碼,因?yàn)槲覀兘?jīng)過Github授權(quán),就可以認(rèn)為完成了登錄認(rèn)證的判斷過程了。

其中GithubClientService類,提供了獲取accessToken和用戶信息的兩個(gè)方法,具體實(shí)現(xiàn)方式如下:

@Service
public class GithubClientService {
	//前面在github中配置時(shí)產(chǎn)生的
    private String clientId = "######";
    private String clientSecret = "######";
    private String state = "123";
    private String redirectUri = "http://localhost:8888/qriver-admin/login/authorization_code";
    @Autowired
    private RestTemplate restTemplate;
    @Nullable
    private WebApplicationContext webApplicationContext;
	//獲取accessToken
    public Map<String, String> queryAccessToken(String code ){
        Map<String, String> map = new HashMap<>();
        map.put("client_id", clientId);
        map.put("client_secret", clientSecret);
        map.put("state", state);
        map.put("code", code);
        map.put("redirect_uri", redirectUri);
        Map<String,String> resp = restTemplate.postForObject("https://github.com/login/oauth/access_token", map, Map.class);
        return resp;
    }
	//獲取用戶信息
    public Map<String, Object> queryUser(String accessToken){
        HttpHeaders httpheaders = new HttpHeaders();
        httpheaders.add("Authorization", "token " + accessToken);
        HttpEntity<?> httpEntity = new HttpEntity<>(httpheaders);
        ResponseEntity<Map> exchange = restTemplate.exchange("https://api.github.com/user", HttpMethod.GET, httpEntity, Map.class);
        System.out.println("exchange.getBody() = " + exchange.getBody());
        return exchange == null ? null : exchange.getBody();
    }
}

其實(shí),完成了上述的配置和方式后,后續(xù)的方式就和短信驗(yàn)證碼的邏輯一樣了,這里我們簡(jiǎn)要的再梳理一下。

首先,我們也需要定義一個(gè)基于Github登錄需要的Authentication實(shí)現(xiàn)類,具體實(shí)現(xiàn)和前面的SmsAuthenticationToken類似,這里不再重復(fù)貼代碼了。

然后,我們?cè)俣x一個(gè)AuthenticationProvider實(shí)現(xiàn)類GithubAuthenticationProvider,具體實(shí)現(xiàn)如下:

@Component
public class GithubAuthenticationProvider implements AuthenticationProvider{
    @Autowired
    @Qualifier("githubUserDetailsService")
    private UserDetailsService userDetailsService;
    @Autowired
    private GithubClientService githubClientService;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        GithubAuthenticationToken token = (GithubAuthenticationToken) authentication;
        String accessToken = (String)token.getPrincipal();
        //根據(jù)accessToken 獲取github用戶信息
        Map<String, Object> userInfo = githubClientService.queryUser(accessToken);
        //然后,根據(jù)github用戶,查詢對(duì)應(yīng)系統(tǒng)用戶信息
        UserDetails user = userDetailsService.loadUserByUsername((String)userInfo.get("login"));
        if (Objects.isNull(user)) {
            throw new InternalAuthenticationServiceException("根據(jù)accessToken:" + accessToken + ",無法獲取對(duì)應(yīng)的用戶信息!");
        }
        GithubAuthenticationToken authenticationResult = new GithubAuthenticationToken(user.getUsername(), user.getAuthorities(), token.getCredentials());
        authenticationResult.setDetails(token.getDetails());
        return authenticationResult;
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return GithubAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

在GithubAuthenticationProvider 類的authenticate()方法中,參數(shù)authentication中對(duì)應(yīng)的是Github授權(quán)后傳遞的accessToken值,我們這里需要根據(jù)accessToken值換取Github用戶信息,這里通過queryUser()方法實(shí)現(xiàn),然后根據(jù)github用戶名去獲取對(duì)應(yīng)的系統(tǒng)用戶信息。如果根據(jù)github用戶名用戶獲取的系統(tǒng)用戶為空,我們可以根據(jù)自己的需求,自動(dòng)生成一個(gè)用戶或者跳轉(zhuǎn)到注冊(cè)頁(yè)面,讓用戶注冊(cè)一個(gè)頁(yè)面,這里為了簡(jiǎn)單,我們直接拋出了一個(gè)異常。

關(guān)于自定義UserDetailsService實(shí)現(xiàn)類,主要需要實(shí)現(xiàn)根據(jù)github用戶名查詢對(duì)應(yīng)系統(tǒng)用戶的功能

當(dāng)認(rèn)證完成后要返回token可以實(shí)現(xiàn)AuthenticationSuccessHandler

import org.springframework.security.core.Authentication;  
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import java.io.IOException;  
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {  
    private final JwtTokenProvider jwtTokenProvider; // 假設(shè)你有一個(gè)JwtTokenProvider類來生成JWT  
    public CustomAuthenticationSuccessHandler(JwtTokenProvider jwtTokenProvider) {  
        this.jwtTokenProvider = jwtTokenProvider;  
    }  
    @Override  
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {  
        // 生成JWT  
        String token = jwtTokenProvider.generateToken(authentication);  
        // 將JWT添加到響應(yīng)頭中  
        response.setHeader("Authorization", "Bearer " + token);  
        // 或者將JWT添加到響應(yīng)體中(取決于你的API設(shè)計(jì))  
        // response.getWriter().write(token);  
        response.setStatus(HttpServletResponse.SC_OK);  
    }  
}

并在securityconfig中設(shè)置

到此這篇關(guān)于SpringSecurity集成第三方登錄的文章就介紹到這了,更多相關(guān)SpringSecurity登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于spring@aspect注解的aop實(shí)現(xiàn)過程代碼實(shí)例

    基于spring@aspect注解的aop實(shí)現(xiàn)過程代碼實(shí)例

    這篇文章主要介紹了基于spring@aspect注解的aop實(shí)現(xiàn)過程代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Java中的延遲隊(duì)列DelayQueue詳細(xì)解析

    Java中的延遲隊(duì)列DelayQueue詳細(xì)解析

    這篇文章主要介紹了Java中的延遲隊(duì)列DelayQueue詳細(xì)解析,JDK自身支持延遲隊(duì)列的數(shù)據(jù)結(jié)構(gòu),其實(shí)類:java.util.concurrent.DelayQueue,<BR>我們通過閱讀源碼的方式理解該延遲隊(duì)列類的實(shí)現(xiàn)過程,需要的朋友可以參考下
    2023-12-12
  • 完美解決java.lang.OutOfMemoryError處理錯(cuò)誤的問題

    完美解決java.lang.OutOfMemoryError處理錯(cuò)誤的問題

    下面小編就為大家?guī)硪黄昝澜鉀Qjava.lang.OutOfMemoryError處理錯(cuò)誤的問題。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • springboot項(xiàng)目連接多種數(shù)據(jù)庫(kù)該如何操作詳析

    springboot項(xiàng)目連接多種數(shù)據(jù)庫(kù)該如何操作詳析

    在Spring Boot應(yīng)用中連接多個(gè)數(shù)據(jù)庫(kù)或數(shù)據(jù)源可以使用多種方式,下面這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目連接多種數(shù)據(jù)庫(kù)該如何操作的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • Spring?Security登錄表單配置示例詳解

    Spring?Security登錄表單配置示例詳解

    這篇文章主要介紹了Spring?Security登錄表單配置,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • java-jwt通過公鑰字符串驗(yàn)證解析token方式

    java-jwt通過公鑰字符串驗(yàn)證解析token方式

    本文示例如何將公鑰字符串轉(zhuǎn)換為RSAPublicKey對(duì)象以校驗(yàn)JWT token,解決了Java-JWT庫(kù)中公鑰格式不匹配的問題,并提供代碼測(cè)試方法
    2025-08-08
  • 解決無法刪除VMware虛擬機(jī)文件的問題及分析

    解決無法刪除VMware虛擬機(jī)文件的問題及分析

    用戶遇到無法刪除VMware文件夾的問題,因系統(tǒng)顯示文件夾正在運(yùn)行,通過任務(wù)管理器終止所有含“vmware”的進(jìn)程后成功刪除,總結(jié)為:強(qiáng)制結(jié)束VMware相關(guān)進(jìn)程可解決文件夾刪除失敗問題,建議后續(xù)遇到類似情況采用此方法
    2025-07-07
  • 利用Java簡(jiǎn)單實(shí)現(xiàn)一個(gè)代碼行數(shù)統(tǒng)計(jì)器方法實(shí)例

    利用Java簡(jiǎn)單實(shí)現(xiàn)一個(gè)代碼行數(shù)統(tǒng)計(jì)器方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于如何利用Java簡(jiǎn)單實(shí)現(xiàn)一個(gè)代碼行數(shù)統(tǒng)計(jì)器的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • GraalVm的反射配置輔助工具agentlib配置及使用

    GraalVm的反射配置輔助工具agentlib配置及使用

    這篇文章主要為大家介紹了GraalVm的反射配置輔助工具agentlib的配置文件及使用說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • 一篇文章總結(jié)Java虛擬機(jī)內(nèi)存區(qū)域模型

    一篇文章總結(jié)Java虛擬機(jī)內(nèi)存區(qū)域模型

    這篇文章主要介紹了一篇文章總結(jié)Java虛擬機(jī)內(nèi)存區(qū)域模型,本篇文章主要來總結(jié)一下Java虛擬機(jī)內(nèi)存的各個(gè)區(qū)域,以及這些區(qū)域的作用、服務(wù)對(duì)象以及其中可能產(chǎn)生的問題,作為大家的面試寶典。,需要的朋友可以參考下
    2019-06-06

最新評(píng)論

恩平市| 南溪县| 衡山县| 长兴县| 眉山市| 灵宝市| 金堂县| 江孜县| 青浦区| 扎赉特旗| 台前县| 浠水县| 土默特左旗| 怀化市| 广平县| 岑溪市| 靖州| 庐江县| 凭祥市| 灵石县| 东城区| 桃源县| 崇义县| 贺兰县| 射洪县| 棋牌| 龙江县| 汶上县| 天门市| 额敏县| 韶关市| 海南省| 柘荣县| 耿马| 茂名市| 河津市| 宣威市| 万年县| 江油市| 砚山县| 仁布县|