JWT双令牌认证:从原理到Spring Boot+Redis实战实现
在实际 Web 应用开发中单纯依赖一个长期有效的 JWT Token 进行身份认证会面临安全与体验的两难选择Token 有效期太短用户需要频繁重新登录有效期太长一旦 Token 泄露系统将长时间处于风险之中。为了解决这个问题大厂普遍采用“双令牌认证”方案使用短期的 access_token 负责接口访问长期的 refresh_token 负责无感刷新配合 Redis 黑名单实现 Token 的即时失效控制。本文将带你从零实现一套完整的 JWT 双令牌认证方案涵盖令牌生成、无感刷新、黑名单管理、安全防护等核心环节并提供生产环境下的配置建议和常见问题排查指南。1. 理解 JWT 双令牌认证的核心机制1.1 为什么需要双令牌设计传统的单 Token 方案存在明显缺陷。如果 Token 有效期设置为 2 小时用户每隔 2 小时就需要重新登录体验极差。如果设置为 30 天一旦 Token 被恶意获取攻击者可以在一个月内任意访问用户数据。双令牌方案通过职责分离解决这个问题access_token短期令牌负责业务接口访问认证有效期通常为 15-30 分钟refresh_token长期令牌仅用于获取新的 access_token有效期通常为 7-30 天当 access_token 过期时前端使用 refresh_token 请求刷新接口获取新的 access_token用户无需重新登录。即使 access_token 泄露由于其有效期很短风险窗口也很小。1.2 无感刷新的工作原理无感刷新的核心流程如下用户登录成功后服务端同时返回 access_token 和 refresh_token前端使用 access_token 访问需要认证的接口当 access_token 过期接口返回 401 状态码前端自动使用 refresh_token 调用刷新接口服务端验证 refresh_token 有效后签发新的 access_token前端使用新的 access_token 重试失败的请求用户无感知这个过程的关键在于前端需要拦截 401 响应并自动触发刷新流程。1.3 黑名单机制的必要性如果没有黑名单机制会出现严重的安全问题refresh_token 一旦签发在有效期内始终可用。如果用户主动退出登录或修改密码旧的 refresh_token 应该立即失效。Redis 黑名单方案通过存储已失效但未过期的 Token 来实现即时失效用户退出登录时将当前有效的 refresh_token 加入黑名单每次使用 refresh_token 时检查该 Token 是否在黑名单中黑名单中的 Token 有效期设置为与原 Token 剩余有效期一致自动过期清理2. 环境准备与项目结构设计2.1 技术栈选择Java 8基础开发语言Spring Boot 2.7Web 框架JJWTJWT 生成和解析库Redis黑名单存储Maven依赖管理2.2 Maven 依赖配置dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version0.11.5/version scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId version0.11.5/scope scoperuntime/scope /dependency /dependencies2.3 项目目录结构src/main/java/com/example/jwtauth/ ├── config/ │ ├── RedisConfig.java │ └── SecurityConfig.java ├── controller/ │ ├── AuthController.java │ └── UserController.java ├── dto/ │ ├── LoginRequest.java │ ├── LoginResponse.java │ └── RefreshRequest.java ├── service/ │ ├── AuthService.java │ └── JwtService.java ├── filter/ │ └── JwtAuthenticationFilter.java └── entity/ └── User.java2.4 Redis 配置# application.yml spring: redis: host: localhost port: 6379 password: database: 0 timeout: 3000ms lettuce: pool: max-active: 8 max-wait: -1ms max-idle: 8 min-idle: 0// RedisConfig.java Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } }3. JWT 工具类设计与实现3.1 JWT 配置参数设计// JwtProperties.java Component ConfigurationProperties(prefix jwt) Data public class JwtProperties { private String secret your-secret-key-at-least-256-bits-long; private Long accessTokenExpire 30 * 60 * 1000L; // 30分钟 private Long refreshTokenExpire 7 * 24 * 60 * 60 * 1000L; // 7天 private String issuer your-app-name; }注意生产环境中的 secret 必须通过环境变量或配置中心管理不能硬编码在代码中。3.2 JWT 服务核心方法// JwtService.java Service Slf4j public class JwtService { Autowired private JwtProperties jwtProperties; Autowired private RedisTemplateString, Object redisTemplate; // 生成 access_token public String generateAccessToken(User user) { return Jwts.builder() .setSubject(user.getUsername()) .claim(userId, user.getId()) .claim(type, access) .setIssuer(jwtProperties.getIssuer()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() jwtProperties.getAccessTokenExpire())) .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecret()) .compact(); } // 生成 refresh_token public String generateRefreshToken(User user) { String refreshToken Jwts.builder() .setSubject(user.getUsername()) .claim(userId, user.getId()) .claim(type, refresh) .setIssuer(jwtProperties.getIssuer()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() jwtProperties.getRefreshTokenExpire())) .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecret()) .compact(); // 存储 refresh_token 与用户的映射关系用于单设备登录控制 String key refresh_token: user.getId(); redisTemplate.opsForValue().set(key, refreshToken, jwtProperties.getRefreshTokenExpire(), TimeUnit.MILLISECONDS); return refreshToken; } // 解析 JWT public Claims parseToken(String token) { try { return Jwts.parser() .setSigningKey(jwtProperties.getSecret()) .parseClaimsJws(token) .getBody(); } catch (ExpiredJwtException e) { log.warn(JWT token expired: {}, e.getMessage()); throw new RuntimeException(Token expired); } catch (Exception e) { log.error(JWT token parse error: {}, e.getMessage()); throw new RuntimeException(Invalid token); } } // 检查 token 是否在黑名单中 public boolean isTokenBlacklisted(String token) { String key blacklist: DigestUtils.md5DigestAsHex(token.getBytes()); return redisTemplate.hasKey(key); } // 将 token 加入黑名单 public void addToBlacklist(String token, long expireTime) { String key blacklist: DigestUtils.md5DigestAsHex(token.getBytes()); redisTemplate.opsForValue().set(key, 1, expireTime, TimeUnit.MILLISECONDS); } }3.3 Token 刷新逻辑实现// AuthService.java Service public class AuthService { Autowired private JwtService jwtService; Autowired private UserRepository userRepository; public LoginResponse refreshToken(String refreshToken) { // 验证 refresh_token 格式和签名 Claims claims jwtService.parseToken(refreshToken); // 检查 token 类型 if (!refresh.equals(claims.get(type))) { throw new RuntimeException(Invalid token type); } // 检查是否在黑名单中 if (jwtService.isTokenBlacklisted(refreshToken)) { throw new RuntimeException(Token has been revoked); } // 获取用户信息 Long userId claims.get(userId, Long.class); User user userRepository.findById(userId) .orElseThrow(() - new RuntimeException(User not found)); // 验证 refresh_token 是否与当前用户绑定的最新 token 一致 String storedToken (String) redisTemplate.opsForValue().get(refresh_token: userId); if (!refreshToken.equals(storedToken)) { // 不一致说明已在其他设备重新登录当前 token 失效 throw new RuntimeException(Token has been replaced); } // 生成新的 access_token String newAccessToken jwtService.generateAccessToken(user); // 将旧的 refresh_token 加入黑名单可选增强安全性 long expireTime claims.getExpiration().getTime() - System.currentTimeMillis(); if (expireTime 0) { jwtService.addToBlacklist(refreshToken, expireTime); } // 生成新的 refresh_token滚动刷新 String newRefreshToken jwtService.generateRefreshToken(user); return LoginResponse.builder() .accessToken(newAccessToken) .refreshToken(newRefreshToken) .expiresIn(jwtProperties.getAccessTokenExpire() / 1000) .build(); } }4. 前端无感刷新实现方案4.1 Axios 拦截器配置// authInterceptor.js import axios from axios; let isRefreshing false; let failedQueue []; const processQueue (error, token null) { failedQueue.forEach(prom { if (error) { prom.reject(error); } else { prom.resolve(token); } }); failedQueue []; }; // 创建 axios 实例 const api axios.create({ baseURL: /api, timeout: 10000 }); // 请求拦截器添加 access_token api.interceptors.request.use( config { const token localStorage.getItem(access_token); if (token) { config.headers.Authorization Bearer ${token}; } return config; }, error Promise.reject(error) ); // 响应拦截器处理 token 刷新 api.interceptors.response.use( response response, error { const originalRequest error.config; // 如果是 401 错误且不是刷新 token 的请求 if (error.response.status 401 !originalRequest._retry) { if (isRefreshing) { // 如果正在刷新将请求加入队列 return new Promise((resolve, reject) { failedQueue.push({ resolve, reject }); }).then(token { originalRequest.headers.Authorization Bearer ${token}; return api(originalRequest); }).catch(err Promise.reject(err)); } originalRequest._retry true; isRefreshing true; const refreshToken localStorage.getItem(refresh_token); if (!refreshToken) { // 没有 refresh_token跳转到登录页 window.location.href /login; return Promise.reject(error); } return new Promise((resolve, reject) { axios.post(/api/auth/refresh, { refreshToken }) .then(response { const { accessToken, refreshToken: newRefreshToken } response.data; // 更新本地存储的 token localStorage.setItem(access_token, accessToken); localStorage.setItem(refresh_token, newRefreshToken); // 更新 Authorization header api.defaults.headers.common.Authorization Bearer ${accessToken}; originalRequest.headers.Authorization Bearer ${accessToken}; // 处理队列中的请求 processQueue(null, accessToken); // 重试原始请求 resolve(api(originalRequest)); }) .catch(err { // 刷新失败清空本地存储并跳转到登录页 localStorage.removeItem(access_token); localStorage.removeItem(refresh_token); processQueue(err, null); window.location.href /login; reject(err); }) .finally(() { isRefreshing false; }); }); } return Promise.reject(error); } ); export default api;4.2 Token 存储策略前端 Token 存储需要考虑安全性和持久化// tokenManager.js class TokenManager { // 使用 localStorage 存储持久化但存在 XSS 风险 static setTokens(accessToken, refreshToken) { localStorage.setItem(access_token, accessToken); localStorage.setItem(refresh_token, refreshToken); } // 或者使用 httpOnly cookie更安全但需要后端配合 static setTokensAsCookie(accessToken, refreshToken) { document.cookie access_token${accessToken}; path/; max-age1800; Secure; SameSiteStrict; document.cookie refresh_token${refreshToken}; path/; max-age604800; Secure; SameSiteStrict; } static clearTokens() { localStorage.removeItem(access_token); localStorage.removeItem(refresh_token); // 清除 cookie document.cookie access_token; path/; expiresThu, 01 Jan 1970 00:00:00 GMT; document.cookie refresh_token; path/; expiresThu, 01 Jan 1970 00:00:00 GMT; } static getAccessToken() { return localStorage.getItem(access_token); } static getRefreshToken() { return localStorage.getItem(refresh_token); } }5. 安全防护与最佳实践5.1 JWT 安全配置要点安全措施配置方式防护目的强密钥至少 256 位随机字符串防止密钥破解合适的有效期access_token: 15-30分钟refresh_token: 7-30天平衡安全与体验HTTPS 传输生产环境强制 HTTPS防止中间人攻击黑名单机制Redis 存储失效 Token即时撤销 Token单设备登录存储最新 refresh_token防止多设备同时登录5.2 防止 Token 泄露的措施// SecurityConfig.java Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf().disable() // 根据前端框架选择是否禁用 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers(/api/auth/login, /api/auth/refresh).permitAll() .anyRequest().authenticated() .and() .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } // 添加安全响应头 Bean public FilterRegistrationBeanCorsFilter corsFilter() { UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); CorsConfiguration config new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin(https://yourdomain.com); // 限制域名 config.addAllowedHeader(*); config.addAllowedMethod(*); source.registerCorsConfiguration(/**, config); FilterRegistrationBeanCorsFilter bean new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; } }5.3 生产环境配置建议# application-prod.yml jwt: secret: ${JWT_SECRET:default-prod-secret-key} # 从环境变量读取 access-token-expire: 900000 # 15分钟 refresh-token-expire: 604800000 # 7天 spring: redis: host: ${REDIS_HOST:redis-server} port: ${REDIS_PORT:6379} password: ${REDIS_PASSWORD:} ssl: true # 生产环境启用 SSL # 日志配置记录认证相关操作 logging: level: com.example.jwtauth.service: DEBUG com.example.jwtauth.filter: DEBUG6. 常见问题排查与解决方案6.1 Token 相关错误排查表问题现象可能原因检查方式解决方案401 Unauthorizedaccess_token 过期或无效检查 Token 有效期和签名使用 refresh_token 刷新刷新接口返回 400refresh_token 无效或黑名单检查黑名单和 Token 绑定重新登录获取新 Token多设备登录互踢单设备登录机制生效检查 refresh_token 绑定设计合理的多设备策略Redis 连接失败配置错误或网络问题检查 Redis 服务状态验证配置和网络连通性6.2 性能优化建议// 使用 Redis 管道批量操作黑名单 public void batchAddToBlacklist(ListString tokens, long expireTime) { redisTemplate.executePipelined(new RedisCallbackObject() { Override public Object doInRedis(RedisConnection connection) throws DataAccessException { for (String token : tokens) { String key blacklist: DigestUtils.md5DigestAsHex(token.getBytes()); connection.setEx(key.getBytes(), expireTime / 1000, 1.getBytes()); } return null; } }); } // 使用本地缓存减少 Redis 访问 Component public class TokenCache { Autowired private RedisTemplateString, Object redisTemplate; private final CacheString, Boolean blacklistCache Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .maximumSize(10000) .build(); public boolean isTokenBlacklisted(String token) { String cacheKey DigestUtils.md5DigestAsHex(token.getBytes()); return blacklistCache.get(cacheKey, key - { String redisKey blacklist: key; return redisTemplate.hasKey(redisKey); }); } }6.3 监控与日志记录// 添加详细的认证日志 Slf4j Service public class AuthService { public LoginResponse login(LoginRequest request) { // ... 登录逻辑 log.info(User {} logged in successfully, issued tokens with expiration: access{}, refresh{}, user.getUsername(), accessExpire, refreshExpire); return response; } public void logout(String refreshToken) { Claims claims jwtService.parseToken(refreshToken); Long userId claims.get(userId, Long.class); // 加入黑名单 long expireTime claims.getExpiration().getTime() - System.currentTimeMillis(); jwtService.addToBlacklist(refreshToken, expireTime); log.info(User {} logged out, token blacklisted with TTL {}ms, userId, expireTime); } }7. 扩展功能与进阶方案7.1 多设备登录管理如果需要支持多设备同时登录可以修改 refresh_token 存储策略// 支持多设备的 refresh_token 管理 public String generateRefreshToken(User user, String deviceId) { String refreshToken // ... 生成 token // 按设备存储 refresh_token String key refresh_token: user.getId() : deviceId; redisTemplate.opsForValue().set(key, refreshToken, jwtProperties.getRefreshTokenExpire(), TimeUnit.MILLISECONDS); return refreshToken; } // 获取用户所有设备的登录状态 public ListString getUserDevices(Long userId) { String pattern refresh_token: userId :*; SetString keys redisTemplate.keys(pattern); return keys.stream() .map(key - key.substring(key.lastIndexOf(:) 1)) .collect(Collectors.toList()); }7.2 权限细粒度控制在 JWT 中嵌入用户角色和权限信息public String generateAccessToken(User user) { SetString permissions userService.getUserPermissions(user.getId()); return Jwts.builder() .setSubject(user.getUsername()) .claim(userId, user.getId()) .claim(type, access) .claim(roles, user.getRoles()) .claim(permissions, permissions) // 添加权限信息 .setIssuer(jwtProperties.getIssuer()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() jwtProperties.getAccessTokenExpire())) .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecret()) .compact(); }7.3 分布式环境适配在微服务架构中需要考虑 Token 的验证和传播// 分布式 Token 验证服务 FeignClient(name auth-service) public interface AuthClient { PostMapping(/api/auth/validate) boolean validateToken(RequestHeader(Authorization) String token); PostMapping(/api/auth/userinfo) UserInfo getUserInfo(RequestHeader(Authorization) String token); } // 网关层统一认证 Component public class AuthFilter implements GlobalFilter { Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token extractToken(exchange.getRequest()); if (requiresAuth(exchange.getRequest()) !authClient.validateToken(token)) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } }这套 JWT 双令牌认证方案在实际项目中经过了充分验证能够有效平衡安全性和用户体验。关键是要根据具体业务需求调整 Token 有效期、黑名单策略和设备管理规则。在生产环境中还需要结合监控告警、日志审计等机制构建完整的安全防护体系。

相关新闻

3分钟解锁微信网页版访问限制:开源插件让你在浏览器中畅聊微信

3分钟解锁微信网页版访问限制:开源插件让你在浏览器中畅聊微信

3分钟解锁微信网页版访问限制:开源插件让你在浏览器中畅聊微信 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 还在为微信网页版频繁出现的…

2026/7/31 9:19:51 阅读更多 →
攻克SD3模型CLIP文件缺失:Krita-AI-Diffusion技术难题的完整解决方案

攻克SD3模型CLIP文件缺失:Krita-AI-Diffusion技术难题的完整解决方案

攻克SD3模型CLIP文件缺失:Krita-AI-Diffusion技术难题的完整解决方案 【免费下载链接】krita-ai-diffusion Streamlined interface for generating images with AI in Krita. Inpaint and outpaint with optional text prompt, no tweaking required. 项目地址: h…

2026/7/31 12:37:04 阅读更多 →
如何用LuLu防火墙重新掌控你的macOS网络连接:从新手到专家的完整指南

如何用LuLu防火墙重新掌控你的macOS网络连接:从新手到专家的完整指南

如何用LuLu防火墙重新掌控你的macOS网络连接:从新手到专家的完整指南 【免费下载链接】LuLu LuLu is the free open-source macOS firewall 项目地址: https://gitcode.com/gh_mirrors/lu/LuLu 在当今数字时代,你的macOS设备每天都会产生数百个网…

2026/7/30 15:52:20 阅读更多 →

最新新闻

Oracle:使用Java存储过程或函数来扩展数据库的功能

Oracle:使用Java存储过程或函数来扩展数据库的功能

在Oracle数据库中,可以使用Java存储过程或函数来扩展数据库的功能。Oracle数据库提供了JDBC (Java Database Connectivity) 支持,这使得Java代码可以直接嵌入到PL/SQL代码中。下面是如何在Oracle数据库中编写一个Java函数的步骤。步骤 1: 确保Java环境已…

2026/7/31 13:30:35 阅读更多 →
C++头文件完全指南:从基础到实战,掌握标准库核心工具

C++头文件完全指南:从基础到实战,掌握标准库核心工具

1. 项目概述:为什么我们需要一份C头文件“地图”?干了这么多年C,我敢说,每个从新手村出来的开发者,都经历过被头文件支配的恐惧。你兴致勃勃地写下一行#include,编译器却冷冰冰地抛出一个“fatal error: io…

2026/7/31 13:30:35 阅读更多 →
微软MAI-Cyber-1-Flash:网络安全AI模型原理与应用实战

微软MAI-Cyber-1-Flash:网络安全AI模型原理与应用实战

如果你正在为网络安全团队招聘发愁,或者每天被海量安全告警淹没却难以快速判断优先级,微软最新发布的 MAI-Cyber-1-Flash 可能正是你需要的解决方案。这不是又一个概念性产品,而是微软首款专门针对网络安全场景优化的生成式 AI 模型&#xff…

2026/7/31 13:30:35 阅读更多 →
当复古遇见开源:Microsoft Comic Chat 的源代码开放意味着什么?

当复古遇见开源:Microsoft Comic Chat 的源代码开放意味着什么?

👋 大家好,我是 带娃的IT创业者,CSDN 人工智能领域新星创作者,一边带娃一边创业的全栈工程师。专注 AI 大模型应用落地、Python 实战进阶与 AI 开发工具链(Python / FastAPI / 大模型 / AI 编程)。 &#x…

2026/7/31 13:30:35 阅读更多 →
Windows SSH连接实战:解决用户名格式与认证失败的完整指南

Windows SSH连接实战:解决用户名格式与认证失败的完整指南

1. 从一次深夜的紧急支持说起 那天晚上十一点,我正打算关电脑,手机突然响了。一个做后端开发的朋友在电话那头语气急促:“老哥,救命!我死活连不上新部署的Windows服务器,明明密码对着呢,SSH一直…

2026/7/31 13:30:34 阅读更多 →
CentOS 7 磁盘配额实验:EXT4 用户/组限额与 XFS Project Quota

CentOS 7 磁盘配额实验:EXT4 用户/组限额与 XFS Project Quota

CentOS 7 磁盘配额实验:EXT4 用户/组限额与 XFS Project Quota1. 服务介绍Linux 磁盘配额(Quota)用于限制普通用户、用户组或指定目录可以占用的磁盘容量和文件数量。它常用于教学服务器、共享文件服务器、邮件服务器和虚拟主机,避…

2026/7/31 13:29:34 阅读更多 →

日新闻

物理复制比逻辑复制好在哪?数据库复制原理详解

物理复制比逻辑复制好在哪?数据库复制原理详解

数据库复制是把主库数据同步到备库的机制,分为逻辑复制和物理复制两种。逻辑复制传输的是 SQL 语句或行变更事件,物理复制传输的是存储引擎底层的物理日志。阿里云 PolarDB(云原生数据库)采用物理复制,在同步延迟、数据…

2026/7/31 0:00:34 阅读更多 →
BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bilib…

2026/7/31 0:00:34 阅读更多 →
有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

当前,游戏行业的“DataAI融合”已从概念验证进入价值落地阶段。根据IDC 2025年数据,中国AI游戏云市场规模已达18.6亿元;同时,游戏研发环节AI渗透率高达86%,生成式AI内容普及率超过50%。面对庞大的市场,游戏…

2026/7/31 0:00:34 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/31 1:03:03 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/31 4:19:39 阅读更多 →

月新闻