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

基于SpringBoot + Redis實(shí)現(xiàn)網(wǎng)站七天免密登錄系統(tǒng)

 更新時(shí)間:2026年04月07日 08:40:39   作者:我愛娃哈哈  
本文介紹了如何使用SpringBoot和Redis實(shí)現(xiàn)七天免密登錄功能,通過合理利用Redis的過期機(jī)制,設(shè)計(jì)了Token策略、Redis存儲(chǔ)結(jié)構(gòu)和安全驗(yàn)證機(jī)制,本文詳細(xì)描述了登錄控制器、攔截器實(shí)現(xiàn)和用戶上下文管理,展示了如何在實(shí)際業(yè)務(wù)中應(yīng)用此功能,需要的朋友可以參考下

引言

最近在優(yōu)化用戶登錄體驗(yàn)時(shí),發(fā)現(xiàn)一個(gè)有意思的現(xiàn)象:用戶平均每天打開APP 3-5次,但每次都要求輸入密碼,體驗(yàn)真的很差。于是我們引入了七天免密登錄功能,用戶勾選"七天內(nèi)自動(dòng)登錄"后,7天內(nèi)無(wú)需輸入密碼,大大提升了用戶體驗(yàn)。

很多同學(xué)可能覺得免密登錄很復(fù)雜,其實(shí)只要合理利用Redis的過期機(jī)制,實(shí)現(xiàn)起來(lái)并不難。今天就來(lái)聊聊如何用SpringBoot + Redis實(shí)現(xiàn)一個(gè)安全可靠的七天免密登錄系統(tǒng)。

為什么需要七天免密登錄?

用戶體驗(yàn)痛點(diǎn)

傳統(tǒng)的登錄方式存在這些問題:

頻繁登錄

  • 用戶每天多次打開APP都要輸入賬號(hào)密碼
  • 忘記密碼導(dǎo)致登錄失敗
  • 手機(jī)端輸入密碼體驗(yàn)差

記憶負(fù)擔(dān)

  • 多個(gè)APP需要記住不同密碼
  • 密碼復(fù)雜度要求高,難以記憶
  • 密碼管理混亂

安全與便利的平衡

  • 短期免密登錄:兼顧安全與便利
  • 長(zhǎng)期記住密碼:安全風(fēng)險(xiǎn)高
  • 永久免密登錄:安全隱患大

核心架構(gòu)設(shè)計(jì)

我們的七天免密登錄架構(gòu):

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   用戶瀏覽器    │───?│   SpringBoot    │───?│   Redis存儲(chǔ)     │
│   (登錄頁(yè)面)    │    │   (認(rèn)證服務(wù))    │    │  (Token管理)   │
└─────────────────┘    └──────────────────┘    └─────────────────┘
        │                        │                       │
        │ 登錄請(qǐng)求(用戶名密碼)     │                       │
        │───────────────────────?│                       │
        │                        │ 生成Token并存儲(chǔ)       │
        │                        │──────────────────────?│
        │  返回Token            │                       │
        │?───────────────────────│                       │
        │                        │                       │
        │ 后續(xù)請(qǐng)求(Token)        │                       │
        │───────────────────────?│                       │
        │                        │ 驗(yàn)證Token            │
        │                        │──────────────────────?│
        │                        │?──────────────────────│
        │                        │                       │

核心設(shè)計(jì)要點(diǎn)

1. Token設(shè)計(jì)策略

// 免密登錄Token實(shí)體
@Data
public class AutoLoginToken {
    private String token;           // 唯一標(biāo)識(shí)
    private Long userId;           // 用戶ID
    private String deviceId;       // 設(shè)備ID
    private String userAgent;      // 用戶代理信息
    private LocalDateTime createTime; // 創(chuàng)建時(shí)間
    private LocalDateTime expireTime; // 過期時(shí)間
    private String ip;             // IP地址(可選)
}

// Token生成策略
@Component
public class TokenGenerator {
    
    public String generateToken(Long userId, String deviceId) {
        // 使用UUID + 用戶ID + 時(shí)間戳生成唯一Token
        String tokenSource = userId + "_" + deviceId + "_" + System.currentTimeMillis();
        return DigestUtils.md5DigestAsHex(tokenSource.getBytes());
    }
}

2. Redis存儲(chǔ)結(jié)構(gòu)

// Redis存儲(chǔ)設(shè)計(jì)
@Component
public class RedisTokenStore {
    
    private static final String TOKEN_PREFIX = "autologin:token:";
    private static final String USER_TOKEN_PREFIX = "autologin:user:";
    private static final int TOKEN_EXPIRE_DAYS = 7;
    
    // 存儲(chǔ)Token信息
    public void storeToken(String token, AutoLoginToken autoLoginToken) {
        String key = TOKEN_PREFIX + token;
        String userKey = USER_TOKEN_PREFIX + autoLoginToken.getUserId();
        
        // 存儲(chǔ)Token詳細(xì)信息
        redisTemplate.opsForValue().set(key, autoLoginToken, 
            TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
        
        // 建立用戶與Token的關(guān)聯(lián)(用于單點(diǎn)登錄控制)
        redisTemplate.opsForValue().set(userKey, token, 
            TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
    }
    
    // 獲取Token信息
    public AutoLoginToken getToken(String token) {
        String key = TOKEN_PREFIX + token;
        return (AutoLoginToken) redisTemplate.opsForValue().get(key);
    }
    
    // 刪除Token
    public void removeToken(String token, Long userId) {
        String key = TOKEN_PREFIX + token;
        String userKey = USER_TOKEN_PREFIX + userId;
        
        redisTemplate.delete(key);
        redisTemplate.delete(userKey);
    }
}

3. 安全驗(yàn)證機(jī)制

// 安全驗(yàn)證策略
@Component
public class TokenValidator {
    
    public boolean validateToken(String token, String deviceId, String userAgent, String ip) {
        AutoLoginToken storedToken = redisTokenStore.getToken(token);
        
        if (storedToken == null) {
            return false;  // Token不存在或已過期
        }
        
        // 驗(yàn)證設(shè)備ID是否匹配
        if (!Objects.equals(storedToken.getDeviceId(), deviceId)) {
            return false;  // 設(shè)備不匹配
        }
        
        // 驗(yàn)證User-Agent是否匹配(防止Token被盜用)
        if (!Objects.equals(storedToken.getUserAgent(), userAgent)) {
            return false;  // User-Agent不匹配
        }
        
        // 可選:驗(yàn)證IP地址(嚴(yán)格模式)
        if (storedToken.getIp() != null && !Objects.equals(storedToken.getIp(), ip)) {
            return false;  // IP地址不匹配
        }
        
        return true;
    }
    
    // 驗(yàn)證通過后,延長(zhǎng)Token有效期
    public void refreshToken(String token) {
        AutoLoginToken storedToken = redisTokenStore.getToken(token);
        if (storedToken != null) {
            // 重新設(shè)置過期時(shí)間為7天
            redisTokenStore.storeToken(token, storedToken);
        }
    }
}

關(guān)鍵實(shí)現(xiàn)細(xì)節(jié)

1. 登錄控制器

@RestController
@RequestMapping("/auth")
public class AuthController {
    
    @PostMapping("/login")
    public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
        // 驗(yàn)證用戶名密碼
        User user = userService.authenticate(request.getUsername(), request.getPassword());
        
        if (user == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                .body(LoginResponse.failed("用戶名或密碼錯(cuò)誤"));
        }
        
        // 創(chuàng)建登錄響應(yīng)
        LoginResponse response = new LoginResponse();
        response.setUserId(user.getId());
        response.setUsername(user.getUsername());
        
        // 如果用戶選擇了七天免密登錄
        if (request.isRememberMe()) {
            String token = tokenGenerator.generateToken(user.getId(), request.getDeviceId());
            
            AutoLoginToken autoLoginToken = new AutoLoginToken();
            autoLoginToken.setToken(token);
            autoLoginToken.setUserId(user.getId());
            autoLoginToken.setDeviceId(request.getDeviceId());
            autoLoginToken.setUserAgent(request.getUserAgent());
            autoLoginToken.setCreateTime(LocalDateTime.now());
            autoLoginToken.setExpireTime(LocalDateTime.now().plusDays(7));
            autoLoginToken.setIp(request.getIp());
            
            redisTokenStore.storeToken(token, autoLoginToken);
            
            response.setToken(token);
            response.setRememberMe(true);
        }
        
        return ResponseEntity.ok(response);
    }
    
    @PostMapping("/auto-login")
    public ResponseEntity<LoginResponse> autoLogin(@RequestBody AutoLoginRequest request) {
        // 驗(yàn)證Token有效性
        boolean isValid = tokenValidator.validateToken(
            request.getToken(), 
            request.getDeviceId(), 
            request.getUserAgent(), 
            request.getIp()
        );
        
        if (!isValid) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                .body(LoginResponse.failed("免密登錄Token無(wú)效"));
        }
        
        // 獲取用戶信息
        AutoLoginToken tokenInfo = redisTokenStore.getToken(request.getToken());
        User user = userService.getById(tokenInfo.getUserId());
        
        // 延長(zhǎng)Token有效期
        tokenValidator.refreshToken(request.getToken());
        
        // 返回登錄成功信息
        LoginResponse response = new LoginResponse();
        response.setUserId(user.getId());
        response.setUsername(user.getUsername());
        response.setToken(request.getToken());
        response.setRememberMe(true);
        
        return ResponseEntity.ok(response);
    }
    
    @PostMapping("/logout")
    public ResponseEntity<String> logout(@RequestBody LogoutRequest request) {
        // 刪除Token
        if (request.getToken() != null) {
            AutoLoginToken tokenInfo = redisTokenStore.getToken(request.getToken());
            if (tokenInfo != null) {
                redisTokenStore.removeToken(request.getToken(), tokenInfo.getUserId());
            }
        }
        
        return ResponseEntity.ok("退出成功");
    }
}

2. 攔截器實(shí)現(xiàn)

@Component
public class AutoLoginInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("Authorization");
        
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            
            boolean isValid = tokenValidator.validateToken(
                token,
                request.getHeader("Device-ID"), 
                request.getHeader("User-Agent"),
                getClientIpAddress(request)
            );
            
            if (isValid) {
                // 設(shè)置當(dāng)前用戶上下文
                AutoLoginToken tokenInfo = redisTokenStore.getToken(token);
                CurrentUserContext.setUserId(tokenInfo.getUserId());
                
                // 延長(zhǎng)Token有效期
                tokenValidator.refreshToken(token);
            }
        }
        
        return true;
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 清理用戶上下文
        CurrentUserContext.clear();
    }
    
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }
        return request.getRemoteAddr();
    }
}

3. 用戶上下文管理

// 當(dāng)前線程用戶上下文
public class CurrentUserContext {
    private static final ThreadLocal<Long> USER_CONTEXT = new ThreadLocal<>();
    
    public static void setUserId(Long userId) {
        USER_CONTEXT.set(userId);
    }
    
    public static Long getUserId() {
        return USER_CONTEXT.get();
    }
    
    public static void clear() {
        USER_CONTEXT.remove();
    }
    
    public static boolean isAuthenticated() {
        return USER_CONTEXT.get() != null;
    }
}

// 用戶信息服務(wù)
@Service
public class CurrentUserService {
    
    public User getCurrentUser() {
        Long userId = CurrentUserContext.getUserId();
        if (userId != null) {
            return userService.getById(userId);
        }
        return null;
    }
    
    public boolean isCurrentUser(Long userId) {
        return Objects.equals(CurrentUserContext.getUserId(), userId);
    }
}

業(yè)務(wù)場(chǎng)景應(yīng)用

1. 登錄頁(yè)面實(shí)現(xiàn)

<!DOCTYPE html>
<html>
<head>
    <title>用戶登錄</title>
</head>
<body>
    <form id="loginForm">
        <div>
            <label>用戶名:</label>
            <input type="text" id="username" required>
        </div>
        <div>
            <label>密碼:</label>
            <input type="password" id="password" required>
        </div>
        <div>
            <input type="checkbox" id="rememberMe"> 
            <label for="rememberMe">七天內(nèi)自動(dòng)登錄</label>
        </div>
        <button type="submit">登錄</button>
    </form>
    <script>
        document.getElementById('loginForm').addEventListener('submit', async function(e) {
            e.preventDefault();
            const formData = {
                username: document.getElementById('username').value,
                password: document.getElementById('password').value,
                rememberMe: document.getElementById('rememberMe').checked,
                deviceId: getDeviceId(), // 生成設(shè)備ID
                userAgent: navigator.userAgent,
                ip: await getClientIP() // 獲取客戶端IP
            };
            const response = await fetch('/auth/login', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify(formData)
            });
            if (response.ok) {
                const data = await response.json();
                if (data.token) {
                    // 保存Token到localStorage(免密登錄用)
                    localStorage.setItem('autologin_token', data.token);
                }
                window.location.href = '/dashboard';
            } else {
                alert('登錄失敗');
            }
        });
    </script>
</body>
</html>

2. 自動(dòng)登錄檢查

// 頁(yè)面加載時(shí)檢查自動(dòng)登錄
window.addEventListener('load', async function() {
    const token = localStorage.getItem('autologin_token');
    if (token) {
        const response = await fetch('/auth/auto-login', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                token: token,
                deviceId: getDeviceId(),
                userAgent: navigator.userAgent,
                ip: await getClientIP()
            })
        });
        
        if (response.ok) {
            const data = await response.json();
            // 自動(dòng)登錄成功,跳轉(zhuǎn)到主頁(yè)
            window.location.href = '/dashboard';
        } else {
            // Token無(wú)效,清除本地存儲(chǔ)
            localStorage.removeItem('autologin_token');
        }
    }
});

3. 安全管理功能

// 安全管理服務(wù)
@Service
public class SecurityManagementService {
    
    // 查看用戶的所有登錄設(shè)備
    public List<LoginDeviceInfo> getUserLoginDevices(Long userId) {
        // 從Redis獲取用戶的所有Token信息
        String userTokenKey = "autologin:user:" + userId;
        String token = (String) redisTemplate.opsForValue().get(userTokenKey);
        
        if (token != null) {
            AutoLoginToken autoLoginToken = redisTokenStore.getToken(token);
            if (autoLoginToken != null) {
                LoginDeviceInfo deviceInfo = new LoginDeviceInfo();
                deviceInfo.setToken(token);
                deviceInfo.setDeviceId(autoLoginToken.getDeviceId());
                deviceInfo.setLastLoginTime(autoLoginToken.getCreateTime());
                deviceInfo.setExpireTime(autoLoginToken.getExpireTime());
                return Arrays.asList(deviceInfo);
            }
        }
        
        return new ArrayList<>();
    }
    
    // 強(qiáng)制注銷某個(gè)設(shè)備
    public void forceLogoutDevice(Long userId, String token) {
        redisTokenStore.removeToken(token, userId);
    }
    
    // 注銷所有設(shè)備
    public void logoutAllDevices(Long userId) {
        // 找到所有相關(guān)Token并刪除
        String userTokenKey = "autologin:user:" + userId;
        String token = (String) redisTemplate.opsForValue().get(userTokenKey);
        
        if (token != null) {
            redisTokenStore.removeToken(token, userId);
        }
    }
}

最佳實(shí)踐建議

1. 安全防護(hù)措施

@Component
public class SecurityEnhancer {
    
    // 防止暴力破解
    private final Map<String, Integer> loginAttemptCount = new ConcurrentHashMap<>();
    private final Map<String, LocalDateTime> lastAttemptTime = new ConcurrentHashMap<>();
    
    public boolean checkLoginAttempt(String username) {
        String key = "login_attempt:" + username;
        Integer count = (Integer) redisTemplate.opsForValue().get(key);
        
        if (count != null && count >= 5) {  // 5次登錄失敗
            return false;  // 暫時(shí)禁止登錄
        }
        
        return true;
    }
    
    public void recordLoginAttempt(String username, boolean success) {
        String key = "login_attempt:" + username;
        
        if (success) {
            redisTemplate.delete(key);  // 登錄成功,清除嘗試記錄
        } else {
            // 登錄失敗,增加嘗試次數(shù)
            redisTemplate.opsForValue().increment(key);
            redisTemplate.expire(key, 30, TimeUnit.MINUTES);  // 30分鐘內(nèi)有效
        }
    }
    
    // 設(shè)備指紋驗(yàn)證
    public String generateDeviceFingerprint(String userAgent, String ip) {
        String fingerprint = userAgent + ":" + ip;
        return DigestUtils.md5DigestAsHex(fingerprint.getBytes());
    }
}

2. 監(jiān)控告警

@Component
public class LoginMonitor {
    
    @EventListener
    public void handleLoginEvent(LoginEvent event) {
        // 記錄登錄日志
        log.info("用戶登錄: userId={}, device={}, ip={}, success={}", 
            event.getUserId(), event.getDeviceId(), event.getIp(), event.isSuccess());
        
        // 監(jiān)控指標(biāo)上報(bào)
        if (event.isSuccess()) {
            MeterRegistry registry = Metrics.globalRegistry;
            registry.counter("login.success").increment();
            registry.timer("login.duration").record(event.getDuration(), TimeUnit.MILLISECONDS);
        } else {
            Metrics.globalRegistry.counter("login.failure").increment();
        }
        
        // 異常登錄檢測(cè)
        if (isSuspiciousLogin(event)) {
            alertService.sendAlert("異常登錄", 
                String.format("用戶 %s 在 %s 從 %s 登錄", 
                    event.getUserId(), event.getDeviceId(), event.getIp()));
        }
    }
    
    private boolean isSuspiciousLogin(LoginEvent event) {
        // 檢查異地登錄、頻繁登錄等異常行為
        return checkGeographicAnomaly(event) || checkFrequencyAnomaly(event);
    }
}

3. 性能優(yōu)化

@Configuration
public class RedisConfig {
    
    // Redis連接池配置
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
            .commandTimeout(Duration.ofSeconds(5))
            .option(SocketOptions::builder)
                .connectTimeout(Duration.ofSeconds(3))
            .build();
        
        RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration();
        serverConfig.setHostName("localhost");
        serverConfig.setPort(6379);
        
        return new LettuceConnectionFactory(serverConfig, clientConfig);
    }
    
    // Token緩存優(yōu)化
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 使用Jackson序列化
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LazyLoadingAwareObjectMapper.getDefaultFactory());
        serializer.setObjectMapper(objectMapper);
        
        template.setValueSerializer(serializer);
        template.setKeySerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        
        return template;
    }
}

預(yù)期效果

通過七天免密登錄方案,我們可以實(shí)現(xiàn):

  • 用戶體驗(yàn)提升:用戶7天內(nèi)無(wú)需重復(fù)登錄,操作更便捷
  • 登錄轉(zhuǎn)化率提高:減少登錄步驟,降低流失率
  • 安全性保障:多重驗(yàn)證機(jī)制,防止Token盜用
  • 運(yùn)維友好:完善的監(jiān)控和管理功能
  • 擴(kuò)展性強(qiáng):支持多種免密時(shí)長(zhǎng)配置

這套方案在保證安全的前提下,極大提升了用戶登錄體驗(yàn),是現(xiàn)代Web應(yīng)用的標(biāo)配功能。

以上就是基于SpringBoot + Redis實(shí)現(xiàn)網(wǎng)站七天免密登錄系統(tǒng)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Redis七天免密登錄的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot如何進(jìn)行對(duì)象復(fù)制的實(shí)踐

    SpringBoot如何進(jìn)行對(duì)象復(fù)制的實(shí)踐

    本文主要介紹了SpringBoot 如何進(jìn)行對(duì)象復(fù)制,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • SpringBoot中的錯(cuò)誤處理機(jī)制源碼解析

    SpringBoot中的錯(cuò)誤處理機(jī)制源碼解析

    這篇文章主要介紹了SpringBoot中的錯(cuò)誤處理機(jī)制源碼解析,springboot根據(jù)訪問者的request中的Accept屬性來(lái)判斷要返回什么樣的數(shù)據(jù),SpringBoot存在一個(gè)錯(cuò)誤處理機(jī)制,會(huì)根據(jù)不同請(qǐng)求返回不同的結(jié)果,需要的朋友可以參考下
    2023-12-12
  • Solon?MVC?的?@Mapping?用法示例說明

    Solon?MVC?的?@Mapping?用法示例說明

    SolonMvc框架中的@Mapping注解用于請(qǐng)求路徑映射,支持加在public方法或類上,它可以自定義路徑、請(qǐng)求方法、內(nèi)容類型等,支持多種路徑映射表達(dá)式和參數(shù)注入方式,本文給大家介紹Solon MVC的@Mapping?用法示例說明,感興趣的朋友一起看看吧
    2024-11-11
  • gateway和jwt網(wǎng)關(guān)認(rèn)證實(shí)現(xiàn)過程解析

    gateway和jwt網(wǎng)關(guān)認(rèn)證實(shí)現(xiàn)過程解析

    這篇文章主要介紹了gateway和jwt網(wǎng)關(guān)認(rèn)證實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Spring中ContextLoaderListener監(jiān)聽詳解

    Spring中ContextLoaderListener監(jiān)聽詳解

    這篇文章主要介紹了Spring中ContextLoaderListener監(jiān)聽詳解,SpringMVC啟動(dòng)時(shí)會(huì)啟動(dòng)WebApplicationContext類型的容器,并且會(huì)調(diào)用之前分析的refresh方法,需要的朋友可以參考下
    2024-01-01
  • Java開發(fā)之HashMap的使用和遍歷

    Java開發(fā)之HashMap的使用和遍歷

    這篇文章主要介紹了Java開發(fā)之HashMap的使用和遍歷的相關(guān)資料,這里提供一個(gè)HashMap的簡(jiǎn)單實(shí)例并結(jié)合List使用,需要的朋友可以參考下
    2017-08-08
  • Java實(shí)現(xiàn)顏色漸變效果

    Java實(shí)現(xiàn)顏色漸變效果

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)顏色漸變效果的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Spring cloud gateway工作流程原理解析

    Spring cloud gateway工作流程原理解析

    這篇文章主要介紹了Spring cloud gateway工作流程原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Java文檔注釋超詳細(xì)講解

    Java文檔注釋超詳細(xì)講解

    這篇文章主要給大家介紹了關(guān)于Java文檔注釋的相關(guān)資料,文檔注釋主要是用來(lái)生成java開發(fā)文檔javadoc的,生成的開發(fā)文檔和Java本身的API幫助文檔是一樣的,需要的朋友可以參考下
    2023-10-10
  • spring中定時(shí)任務(wù)taskScheduler的詳細(xì)介紹

    spring中定時(shí)任務(wù)taskScheduler的詳細(xì)介紹

    這篇文章主要介紹了spring中定時(shí)任務(wù)taskScheduler的相關(guān)資料,文中通過示例代碼介紹的很詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,有需要的朋友們下面來(lái)一起看看吧。
    2017-02-02

最新評(píng)論

洪泽县| 陇南市| 崇州市| 太白县| 靖安县| 东至县| 右玉县| 洛阳市| 清水河县| 新乡市| 朝阳市| 元江| 大竹县| 黄梅县| 额敏县| 孟州市| 正蓝旗| 当涂县| 横山县| 青浦区| 丹阳市| 舒城县| 齐齐哈尔市| 西乡县| 德昌县| 巧家县| 松江区| 阳春市| 合阳县| 自贡市| 射阳县| 财经| 沁水县| 孟村| 彰武县| 德保县| 青河县| 山东省| 乌鲁木齐市| 崇州市| 大安市|