Spring Boot用户状态检测系统:睡眠状态识别与智能提醒实战
最近在开发一个智能提醒系统时遇到了一个有趣的技术需求如何准确识别用户状态并触发相应的提醒逻辑。特别是在睡眠状态检测这个场景下传统的方案往往依赖硬件传感器或复杂的生物特征分析但在某些轻量级应用中我们完全可以通过软件层面的状态管理来实现类似功能。本文将围绕状态检测与提醒系统的技术实现分享一套完整的解决方案涵盖状态建模、事件触发、消息推送等核心环节适合移动端和后端开发者参考使用。1. 状态检测的技术背景与应用场景1.1 什么是用户状态检测用户状态检测是指通过软件系统识别用户当前的活动状态如在线、离线、忙碌、空闲、睡眠等。在即时通讯、智能提醒、健康管理等应用中准确的状态判断能够显著提升用户体验。与硬件检测方案相比纯软件方案的优势在于部署成本低、兼容性好但需要更精细的数据建模和算法设计。1.2 典型应用场景分析在实际项目中状态检测技术可以应用于多个场景智能消息推送根据用户状态调整推送策略避免在睡眠时段打扰用户自动化工作流结合状态信息触发相应的业务流程如勿扰模式下的自动回复健康管理通过分析用户作息规律提供个性化的健康建议社交应用显示好友的实时状态增强社交互动的时效性2. 技术选型与环境准备2.1 核心技术与框架实现状态检测系统需要以下技术组件数据采集层移动端SDKAndroid/iOS或Web API用于收集用户行为数据数据处理层使用Spring Boot构建后端服务负责状态计算和逻辑判断消息推送集成第三方推送服务如极光推送、个推或自建WebSocket连接数据存储MySQL用于存储用户配置Redis用于缓存实时状态2.2 开发环境配置示例环境配置如下# Java环境 java version 11.0.12 Spring Boot 2.7.0 # 数据库 MySQL 8.0.28 Redis 6.2.6 # 构建工具 Maven 3.8.12.3 项目结构规划建议采用标准的分层架构src/ ├── main/ │ ├── java/ │ │ └── com/example/status/ │ │ ├── controller/ # 控制层 │ │ ├── service/ # 业务层 │ │ ├── repository/ # 数据层 │ │ ├── model/ # 实体类 │ │ └── config/ # 配置类 │ └── resources/ │ ├── application.yml # 主配置文件 │ └── static/ # 静态资源3. 状态建模与核心算法3.1 用户状态数据模型设计首先定义用户状态的核心实体类// 文件路径src/main/java/com/example/status/model/UserStatus.java public class UserStatus { private Long userId; private StatusType currentStatus; // 当前状态 private LocalDateTime lastUpdateTime; // 最后更新时间 private String timezone; // 用户时区 private SleepSchedule sleepSchedule; // 睡眠计划配置 // 枚举定义状态类型 public enum StatusType { ONLINE, // 在线 OFFLINE, // 离线 BUSY, // 忙碌 SLEEPING, // 睡眠中 AWAY // 离开 } // 睡眠计划配置类 public static class SleepSchedule { private LocalTime usualBedtime; // 通常就寝时间 private LocalTime usualWakeupTime; // 通常起床时间 private boolean autoDetection; // 是否启用自动检测 } }3.2 状态判断算法实现基于时间和用户行为的复合判断逻辑// 文件路径src/main/java/com/example/status/service/StatusDetectionService.java Service public class StatusDetectionService { Autowired private UserStatusRepository statusRepository; public UserStatus detectCurrentStatus(Long userId) { UserStatus userStatus statusRepository.findByUserId(userId); if (userStatus null) { return createDefaultStatus(userId); } // 多重条件判断 if (isSleepingBySchedule(userStatus)) { userStatus.setCurrentStatus(UserStatus.StatusType.SLEEPING); } else if (isSleepingByActivity(userStatus)) { userStatus.setCurrentStatus(UserStatus.StatusType.SLEEPING); } else { userStatus.setCurrentStatus(detectOtherStatus(userStatus)); } userStatus.setLastUpdateTime(LocalDateTime.now()); return statusRepository.save(userStatus); } private boolean isSleepingBySchedule(UserStatus status) { LocalTime now LocalTime.now(); LocalTime bedtime status.getSleepSchedule().getUsualBedtime(); LocalTime wakeupTime status.getSleepSchedule().getUsualWakeupTime(); // 处理跨夜时间判断 if (bedtime.isAfter(wakeupTime)) { return now.isAfter(bedtime) || now.isBefore(wakeupTime); } else { return now.isAfter(bedtime) now.isBefore(wakeupTime); } } private boolean isSleepingByActivity(UserStatus status) { // 基于用户最后活动时间判断 // 如果超过一定时间无活动可能处于睡眠状态 Duration inactiveDuration Duration.between( status.getLastUpdateTime(), LocalDateTime.now()); return inactiveDuration.toHours() 6; // 6小时无活动视为睡眠 } }4. 完整实战案例睡眠状态检测系统4.1 数据库表结构设计创建用户状态管理相关的数据表-- 用户状态表 CREATE TABLE user_status ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL UNIQUE, current_status VARCHAR(20) NOT NULL DEFAULT OFFLINE, last_update_time DATETIME NOT NULL, timezone VARCHAR(50) DEFAULT Asia/Shanghai, usual_bedtime TIME, usual_wakeup_time TIME, auto_detection BOOLEAN DEFAULT true, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -- 用户活动记录表 CREATE TABLE user_activity ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL, activity_type VARCHAR(30) NOT NULL, activity_time DATETIME NOT NULL, device_info VARCHAR(200), INDEX idx_user_time (user_id, activity_time) );4.2 Spring Boot 核心配置应用配置文件示例# 文件路径src/main/resources/application.yml spring: datasource: url: jdbc:mysql://localhost:3306/status_db?useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 password: database: 0 jpa: hibernate: ddl-auto: update show-sql: true app: status: detection: sleep-threshold-hours: 6 check-interval-minutes: 54.3 状态检测定时任务实现定时状态检测和更新// 文件路径src/main/java/com/example/status/scheduler/StatusUpdateScheduler.java Component Slf4j public class StatusUpdateScheduler { Autowired private StatusDetectionService statusDetectionService; Autowired private UserStatusRepository userStatusRepository; Scheduled(fixedRate 300000) // 每5分钟执行一次 public void autoUpdateUserStatus() { log.info(开始自动更新用户状态); ListLong activeUserIds userStatusRepository.findActiveUserIds(); for (Long userId : activeUserIds) { try { UserStatus updatedStatus statusDetectionService.detectCurrentStatus(userId); log.debug(用户 {} 状态更新为: {}, userId, updatedStatus.getCurrentStatus()); } catch (Exception e) { log.error(更新用户 {} 状态失败: {}, userId, e.getMessage()); } } } }4.4 RESTful API 接口实现提供状态查询和管理的API接口// 文件路径src/main/java/com/example/status/controller/StatusController.java RestController RequestMapping(/api/status) Validated public class StatusController { Autowired private StatusDetectionService statusDetectionService; GetMapping(/{userId}) public ResponseEntityUserStatus getCurrentStatus(PathVariable Long userId) { UserStatus status statusDetectionService.detectCurrentStatus(userId); return ResponseEntity.ok(status); } PostMapping(/{userId}/sleep) public ResponseEntityString setSleepStatus(PathVariable Long userId) { UserStatus status statusDetectionService.detectCurrentStatus(userId); status.setCurrentStatus(UserStatus.StatusType.SLEEPING); status.setLastUpdateTime(LocalDateTime.now()); // 保存更新 statusDetectionService.updateStatus(status); return ResponseEntity.ok(睡眠状态设置成功); } PutMapping(/{userId}/schedule) public ResponseEntityString updateSleepSchedule( PathVariable Long userId, RequestBody SleepScheduleRequest request) { // 更新用户睡眠计划 statusDetectionService.updateSleepSchedule(userId, request); return ResponseEntity.ok(睡眠计划更新成功); } }4.5 前端状态展示组件简单的Vue.js组件示例展示如何显示用户状态!-- 文件路径src/main/resources/static/js/status-display.vue -- template div classstatus-container div classstatus-indicator :classstatusClass {{ statusText }} /div div classlast-update 最后更新: {{ lastUpdateTime }} /div /div /template script export default { props: { userId: { type: Number, required: true } }, data() { return { currentStatus: null, lastUpdateTime: null } }, computed: { statusClass() { return { status-online: this.currentStatus ONLINE, status-sleeping: this.currentStatus SLEEPING, status-busy: this.currentStatus BUSY } }, statusText() { const statusMap { ONLINE: 在线, SLEEPING: 睡眠中, BUSY: 忙碌, OFFLINE: 离线 } return statusMap[this.currentStatus] || 未知状态 } }, mounted() { this.fetchStatus() setInterval(this.fetchStatus, 300000) // 每5分钟更新一次 }, methods: { async fetchStatus() { try { const response await fetch(/api/status/${this.userId}) const data await response.json() this.currentStatus data.currentStatus this.lastUpdateTime this.formatTime(data.lastUpdateTime) } catch (error) { console.error(获取状态失败:, error) } }, formatTime(timestamp) { return new Date(timestamp).toLocaleString(zh-CN) } } } /script style .status-container { padding: 10px; border-radius: 5px; background: #f5f5f5; } .status-indicator { display: inline-block; padding: 4px 8px; border-radius: 3px; color: white; font-size: 12px; } .status-online { background: #52c41a; } .status-sleeping { background: #faad14; } .status-busy { background: #f5222d; } /style5. 常见问题与解决方案5.1 状态判断准确性问题问题现象系统错误地将活跃用户判断为睡眠状态可能原因时区配置错误导致时间判断偏差用户活动数据采集不完整睡眠阈值设置不合理解决方案// 增强时区处理逻辑 public class TimeZoneUtils { public static LocalDateTime convertToUserTimezone(LocalDateTime serverTime, String userTimezone) { ZoneId serverZone ZoneId.systemDefault(); ZoneId userZone ZoneId.of(userTimezone); return serverTime.atZone(serverZone) .withZoneSameInstant(userZone) .toLocalDateTime(); } } // 优化活动检测逻辑 public class EnhancedActivityDetector { public boolean hasRecentActivity(Long userId, Duration maxInactiveDuration) { // 检查多种活动类型登录、消息发送、页面浏览等 ListActivityType relevantActivities Arrays.asList( ActivityType.LOGIN, ActivityType.MESSAGE_SEND, ActivityType.PAGE_VIEW ); return activityRepository.existsRecentActivity( userId, relevantActivities, maxInactiveDuration); } }5.2 性能优化策略问题现象用户量增大后系统响应变慢优化方案使用Redis缓存热点用户状态实现状态变化的增量更新采用分库分表策略// Redis缓存实现 Component public class StatusCacheService { Autowired private RedisTemplateString, Object redisTemplate; private static final String STATUS_KEY_PREFIX user:status:; private static final Duration CACHE_TTL Duration.ofMinutes(10); public void cacheUserStatus(UserStatus status) { String key STATUS_KEY_PREFIX status.getUserId(); redisTemplate.opsForValue().set(key, status, CACHE_TTL); } public UserStatus getCachedStatus(Long userId) { String key STATUS_KEY_PREFIX userId; return (UserStatus) redisTemplate.opsForValue().get(key); } }6. 最佳实践与工程建议6.1 数据一致性与事务管理在状态更新过程中确保数据一致性Service Transactional public class StatusManagementService { public void updateStatusWithTransaction(Long userId, StatusType newStatus) { try { // 1. 更新数据库状态 UserStatus status statusRepository.findByUserId(userId); status.setCurrentStatus(newStatus); status.setLastUpdateTime(LocalDateTime.now()); statusRepository.save(status); // 2. 更新缓存 statusCacheService.cacheUserStatus(status); // 3. 发送状态变更事件 eventPublisher.publishEvent(new StatusChangeEvent(this, userId, newStatus)); } catch (Exception e) { // 事务回滚确保数据一致性 throw new RuntimeException(状态更新失败, e); } } }6.2 监控与日志记录建立完善的监控体系Aspect Component Slf4j public class StatusMonitoringAspect { Around(execution(* com.example.status.service.*.*(..))) public Object monitorServiceMethods(ProceedingJoinPoint joinPoint) throws Throwable { String methodName joinPoint.getSignature().getName(); long startTime System.currentTimeMillis(); try { Object result joinPoint.proceed(); long executionTime System.currentTimeMillis() - startTime; log.info(方法 {} 执行成功耗时: {}ms, methodName, executionTime); // 记录指标到监控系统 Metrics.counter(status_service_method, method, methodName) .increment(); Metrics.timer(status_service_duration, method, methodName) .record(executionTime, TimeUnit.MILLISECONDS); return result; } catch (Exception e) { log.error(方法 {} 执行失败: {}, methodName, e.getMessage()); Metrics.counter(status_service_error, method, methodName) .increment(); throw e; } } }6.3 安全与权限控制确保状态信息的安全访问Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers(/api/status/**).authenticated() .antMatchers(/api/admin/**).hasRole(ADMIN) .anyRequest().permitAll() .and() .oauth2ResourceServer().jwt(); } } // 方法级权限控制 Service public class SecureStatusService { PreAuthorize(#userId authentication.principal.id or hasRole(ADMIN)) public UserStatus getStatusSecurely(Long userId) { return statusDetectionService.detectCurrentStatus(userId); } }7. 扩展功能与进阶优化7.1 机器学习增强的状态预测基于历史数据训练预测模型# 文件路径scripts/status_predictor.py import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split class StatusPredictor: def __init__(self): self.model RandomForestClassifier(n_estimators100) def train(self, historical_data): # 特征工程时间特征、行为模式、历史状态等 features self.extract_features(historical_data) labels historical_data[status] X_train, X_test, y_train, y_test train_test_split( features, labels, test_size0.2) self.model.fit(X_train, y_train) accuracy self.model.score(X_test, y_test) print(f模型准确率: {accuracy:.2f}) def predict_next_status(self, user_data): features self.extract_features([user_data]) prediction self.model.predict(features) return prediction[0]7.2 多维度状态融合分析结合多个数据源提高判断准确性public class MultiSourceStatusDetector { public StatusType detectWithMultipleSources(Long userId) { // 1. 基于时间规律的分析 TimeBasedAnalysis timeAnalysis analyzeTimePattern(userId); // 2. 基于行为模式的分析 BehaviorAnalysis behaviorAnalysis analyzeBehaviorPattern(userId); // 3. 基于设备传感器的分析如果可用 SensorDataAnalysis sensorAnalysis analyzeSensorData(userId); // 4. 加权融合决策 return fuseDecisions(timeAnalysis, behaviorAnalysis, sensorAnalysis); } private StatusType fuseDecisions(AnalysisResult... analyses) { MapStatusType, Double scores new HashMap(); for (AnalysisResult analysis : analyses) { for (Map.EntryStatusType, Double entry : analysis.getConfidenceScores().entrySet()) { scores.merge(entry.getKey(), entry.getValue(), Double::sum); } } return scores.entrySet().stream() .max(Map.Entry.comparingByValue()) .map(Map.Entry::getKey) .orElse(StatusType.OFFLINE); } }本文详细介绍了用户状态检测系统的完整实现方案从基础概念到实战代码涵盖了系统设计的各个环节。在实际项目中建议根据具体业务需求调整判断逻辑和参数设置特别是在处理用户隐私数据时要严格遵守相关法律法规。通过合理的架构设计和持续的优化迭代可以构建出既准确又高效的智能状态管理系统。

相关新闻

Java中文乱码全解析:从字符编码原理到实战解决方案

Java中文乱码全解析:从字符编码原理到实战解决方案

1. 从“锟斤拷”说起:为什么中文乱码是Java开发者的必修课如果你在Java开发中没见过“锟斤拷”或者“烫烫烫”,那你的职业生涯可能还不够完整。这当然是个玩笑,但背后反映的是一个严肃且普遍的问题:中文乱码。它就像一个幽灵&…

2026/7/30 3:55:32阅读更多 →
Python数据分析实战:从数据清洗到可视化呈现的完整行业盈利分析流程

Python数据分析实战:从数据清洗到可视化呈现的完整行业盈利分析流程

1. 项目缘起:为什么我们需要一个“闯关式”的行业盈利分析实验?最近在带团队做数据分析培训,发现一个挺普遍的问题:很多朋友学了Python、Pandas、Matplotlib,看教程时感觉都懂了,一到自己动手分析真实的行业…

2026/7/30 3:55:32阅读更多 →
verilog HDLBits刷题[Finite State Machines]“Lemmings2”---Lemmings2

verilog HDLBits刷题[Finite State Machines]“Lemmings2”---Lemmings2

1、题目 See also: Lemmings1. In addition to walking left and right, Lemmings will fall (and presumably go "aaah!") if the ground disappears underneath them. In addition to walking left and right and changing direction when bumped, when ground0…

2026/7/30 3:55:32阅读更多 →
从零开始:Node.js接入Milvus向量数据库实战(AI日记本场景)

从零开始:Node.js接入Milvus向量数据库实战(AI日记本场景)

手把手教你用Milvus实现语义搜索,解决LLM幻觉问题 前言 最近在做AI日记本项目,遇到了一个痛点:用户想"找出最近情绪积极的日记",传统的MySQL用LIKE %开心%根本搜不准。这时候就需要向量数据库出场了。 本文会带你快速…

2026/7/30 5:09:49阅读更多 →
手机变游戏掌机:Winlator让Android流畅运行Windows游戏

手机变游戏掌机:Winlator让Android流畅运行Windows游戏

手机变游戏掌机:Winlator让Android流畅运行Windows游戏 【免费下载链接】winlator Android application for running Windows applications with Wine and Box86/Box64 项目地址: https://gitcode.com/GitHub_Trending/wi/winlator 你是否想过在手机上玩《GT…

2026/7/30 5:09:49阅读更多 →
具身机器人高温胶选哪种?2026机器人耐高温粘接胶选型指南

具身机器人高温胶选哪种?2026机器人耐高温粘接胶选型指南

具身机器人在运行过程中,关节模组、电机组件、传感器以及内部结构件都会产生热量,同时还需要长期承受振动、冲击和重复运动。因此,机器人装配过程中选择合适的高温胶,对于提升结构可靠性和使用寿命十分关键。那么具身机器人高温胶…

2026/7/30 5:09:49阅读更多 →
电子系统设计:从单元电路到系统集成的核心思维与实践

电子系统设计:从单元电路到系统集成的核心思维与实践

1. 从“电路”到“系统”:第十一章的核心视角转换学电子技术,很多人卡在从分析单个电路到理解一个完整电子系统的门槛上。李雪飞老师的《电子技术基础》这本书,前面的章节把三极管、运放、门电路这些“砖瓦”讲得很透,但到了第十一…

2026/7/30 5:09:49阅读更多 →
如何永久保存微信聊天记录?3种格式导出完整指南

如何永久保存微信聊天记录?3种格式导出完整指南

如何永久保存微信聊天记录?3种格式导出完整指南 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatMsg …

2026/7/30 5:09:49阅读更多 →
React createPortal 实战:模态框逃出 overflow:hidden、事件冒泡与焦点管理

React createPortal 实战:模态框逃出 overflow:hidden、事件冒泡与焦点管理

React createPortal 实战:模态框逃出 overflow:hidden、事件冒泡与焦点管理 写模态框(Modal)时你大概率遇到过这个诡异现象:弹窗明明该盖住全屏,结果只在某个卡片内部显示一小块,还被父容器的滚动条截断了。加 z-index: 9999 也没用。 问题不在层级,在于 DOM 结构。这篇用 crea…

2026/7/30 5:07:48阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/29 9:47:45阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/29 7:00:19阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/29 7:58:51阅读更多 →
3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 [特殊字符]

3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 [特殊字符]

3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 🚀 【免费下载链接】TrollInstallerX A TrollStore installer for iOS 14.0 - 16.6.1 项目地址: https://gitcode.com/gh_mirrors/tr/TrollInstallerX 你是否曾经因为iOS系统的严格…

2026/7/30 0:00:58阅读更多 →
[GESP202606 四级] 扫雷

[GESP202606 四级] 扫雷

B4557 [GESP202606 四级] 扫雷 https://www.luogu.com.cn/problem/B4557 中国计算机学会(CCF)2026年6月C四级讲解——扫雷 https://www.bilibili.com/video/BV1MCMg6AEXR/ B4557 [GESP202606 四级] 扫雷 https://www.bilibili.com/video/BV1ZKTj6ZEVh/ 2…

2026/7/30 0:00:58阅读更多 →
Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 您是否曾因Windows系统盘空间不足而烦恼?是否遇到过设…

2026/7/30 0:00:58阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/30 0:27:26阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/30 4:47:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/29 14:26:42阅读更多 →