{"repo": "chenfromchina123/aispring", "files": {"docs/PROJECT_TECH_OVERVIEW.md": {"e8e062a225b43bf79ca9e278530fca7c457c0fcd": {"t": 1785746586.4588833, "n": 41965, "h": "fcfb48007809378c", "c": "# AI智能学习助手系统 - 技术架构详解\n\n> 本文档详细记录系统的技术实现细节,涵盖架构设计、核心模块实现、安全机制、性能优化等方面,可作为面试技术深度的参考材料。\n\n---\n\n## 一、系统架构概览\n\n### 1.1 整体架构设计\n\n本系统采用**前后端分离 + 微服务化**的架构模式,由三个核心子系统组成:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│ 用户层 (Browser) │\n└─────────────────────────────────────────────────────────────────────────┘\n │\n ┌───────────────┼───────────────┐\n ▼ ▼ ▼\n ┌──────────────┐ ┌──────────────┐ ┌──────────────┐\n │ vue-app │ │ word-game │ │ Nginx │\n │ (Vue 3) │ │ (Vue 3) │ │ 反向代理 │\n │ Port: 3000 │ │ Port: 5200 │ │ │\n └──────────────┘ └──────────────┘ └──────────────┘\n │ │\n └───────┬───────┘\n ▼\n ┌──────────────────────────────┐\n │ aispring 后端 │\n │ (Spring Boot 3.3.5) │\n │ Port: 5000 │\n └──────────────────────────────┘\n │\n ┌───────────────┼───────────────┐\n ▼ ▼ ▼\n ┌──────────────┐ ┌──────────────┐ ┌──────────────┐\n │ MySQL │ │ Redis │ │ AI Services │\n │ (主数据库) │ │ (缓存/限流) │ │ DeepSeek/豆包 │\n └──────────────┘ └──────────────┘ └──────────────┘\n │\n ▼\n ┌──────────────────────────────┐\n │ word-game-server │\n │ (Express 5 + SQLite) │\n │ Port: 5201 │\n └──────────────────────────────┘\n```\n\n### 1.2 技术栈总览\n\n| 层级 | 技术选型 | 版本 | 选型理由 |\n| -------------- | --------------------- | ------ | ----------------------------------------------- |\n| **后端框架** | Spring Boot | 3.3.5 | 企业级Java框架,生态完善,支持响应式编程 |\n| **前端框架** | Vue 3 | 3.4.0 | Composition API,更好的TypeScript支持,性能优化 |\n| **构建工具** | Vite | 5.0.0 | ES Module原生支持,HMR速度快,打包体积小 |\n| **状态管理** | Pinia | 2.1.7 | Vue官方推荐,TypeScript友好,模块化设计 |\n| **数据库** | MySQL | 8.x | 关系型数据库,支持复杂查询和事务 |\n| **缓存** | Redis | 7.x | 高性能内存数据库,支持限流、会话管理 |\n| **ORM** | Spring Data JPA | 3.x | 简化数据访问层开发,支持方法命名查询 |\n| **认证** | JWT + Spring Security | 0.12.3 | 无状态认证,支持分布式部署 |\n| **AI集成** | Spring AI | 0.8.1 | 官方AI集成框架,统一API调用方式 |\n| **数据库迁移** | Flyway | 9.x | 版本化数据库变更管理 |\n\n---\n\n## 二、后端架构详解 (aispring)\n\n### 2.1 项目结构\n\n```\naispring/\n├── src/main/java/com/aispring/\n│ ├── config/ # 配置类\n│ │ ├── SecurityConfig.java # Spring Security 安全配置\n│ │ ├── RedisConfig.java # Redis 缓存配置\n│ │ ├── CorsConfig.java # 跨域配置\n│ │ ├── JacksonConfig.java # JSON 序列化配置\n│ │ └── StorageProperties.java # 文件存储配置\n│ ├── controller/ # 控制器层 (REST API)\n│ │ ├── AuthController.java # 认证相关\n│ │ ├── AiChatController.java # AI 对话\n│ │ ├── CloudDiskController.java # 云盘管理\n│ │ └── ...\n│ ├── service/ # 服务层 (业务逻辑)\n│ │ ├── impl/ # 服务实现\n│ │ ├── AiChatService.java\n│ │ ├── AuthService.java\n│ │ └── ...\n│ ├── repository/ # 数据访问层 (JPA)\n│ ├── entity/ # 实体类\n│ ├── dto/ # 数据传输对象\n│ │ ├── request/ # 请求DTO\n│ │ └── response/ # 响应DTO\n│ ├── security/ # 安全相关\n│ │ ├── JwtAuthenticationFilter.java\n│ │ ├── CustomUserDetails.java\n│ │ └── UserDetailsServiceImpl.java\n│ ├── graphql/ # GraphQL 支持\n│ └── exception/ # 异常处理\n├── migrations/ # Flyway 数据库迁移脚本\n└── pom.xml # Maven 依赖配置\n```\n\n### 2.2 核心依赖分析 (pom.xml)\n\n```xml\n\n\n org.springframework.boot\n spring-boot-starter-web\n\n\n\n\n org.springframework.boot\n spring-boot-starter-data-jpa\n\n\n\n\n org.springframework.boot\n spring-boot-starter-security\n\n\n\n\n io.jsonwebtoken\n jjwt-api\n 0.12.3\n\n\n\n\n org.springframework.ai\n spring-ai-openai-spring-boot-starter\n 0.8.1\n\n\n\n\n org.springframework.boot\n spring-boot-starter-graphql\n\n\n\n\n org.springframework.boot\n spring-boot-starter-data-redis\n\n\n\n\n org.flywaydb\n flyway-core\n\n```\n\n**技术选型关键点:**\n\n- **Spring Boot 3.x** 要求 **Java 17+**,支持 Virtual Threads(虚拟线程)\n- **Spring AI 0.8.1** 提供统一的 AI 模型调用抽象层,支持 OpenAI 兼容 API\n- **JJWT 0.12.3** 支持 JWT 的创建、解析和验证,支持多种签名算法\n\n### 2.3 安全架构设计\n\n#### 2.3.1 Spring Security 配置\n\n```java\n@Configuration\n@EnableWebSecurity\n@EnableMethodSecurity\n@RequiredArgsConstructor\npublic class SecurityConfig {\n\n private final JwtAuthenticationFilter jwtAuthFilter;\n\n @Bean\n public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n http\n .csrf(csrf -> csrf.disable()) // 禁用 CSRF(前后端分离架构)\n .cors(cors -> {}) // 启用 CORS\n .authorizeHttpRequests(auth -> auth\n // OPTIONS 预检请求放行\n .requestMatchers(HttpMethod.OPTIONS, \"/**\").permitAll()\n // SSE 异步分发放行\n .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()\n // 公开端点\n .requestMatchers(\"/api/auth/**\").permitAll()\n .requestMatchers(\"/api/ask\", \"/api/ask-stream\").permitAll()\n // 其他需要认证\n .anyRequest().authenticated()\n )\n .sessionManagement(session -> session\n .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话\n )\n .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);\n\n return http.build();\n }\n\n @Bean\n public PasswordEncoder passwordEncoder() {\n return new BCryptPasswordEncoder(); // BCrypt 密码加密\n }\n}\n```\n\n**面试要点:**\n\n1. **为什么禁用 CSRF?** 前后端分离架构,使用 JWT Token 认证,不依赖 Cookie-Session 机制\n2. **无状态会话的意义**:服务端不存储会话信息,便于水平扩展和负载均衡\n3. **BCrypt 加密优势**:自动加盐、计算成本可调、抗彩虹表攻击\n\n#### 2.3.2 JWT 认证过滤器\n\n```java\n@Component\n@RequiredArgsConstructor\npublic class JwtAuthenticationFilter extends OncePerRequestFilter {\n\n private final JwtUtil jwtUtil;\n private final UserDetailsService userDetailsService;\n\n private static final String[] PUBLIC_PATTERNS = {\n \"/api/auth/**\", \"/swagger-ui/**\", \"/api/public-files/**\"\n };\n\n private final AntPathMatcher pathMatcher = new AntPathMatcher();\n\n @Override\n protected boolean shouldNotFilter(HttpServletRequest request) {\n // OPTIONS 请求和公开路径跳过过滤\n if (\"OPTIONS\".equalsIgnoreCase(request.getMethod())) return true;\n\n String path = request.getServletPath();\n for (String pattern : PUBLIC_PATTERNS) {\n if (pathMatcher.match(pattern, path)) return true;\n }\n return false;\n }\n\n @Override\n protected void doFilterInternal(HttpServletRequest request,\n HttpServletResponse response,\n FilterChain filterChain) {\n final String authHeader = request.getHeader(\"Authorization\");\n\n if (authHeader == null || !authHeader.startsWith(\"Bearer \")) {\n filterChain.doFilter(request, response);\n return;\n }\n\n final String jwt = authHeader.substring(7);\n final String userEmail = jwtUtil.extractUsername(jwt);\n\n if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {\n UserDetails userDetails = userDetailsService.loadUserByUsername(userEmail);\n\n if (jwtUtil.isTokenValid(jwt, userDetails)) {\n UsernamePasswordAuthenticationToken authToken =\n new UsernamePasswordAuthenticationToken(\n userDetails, null, userDetails.getAuthorities()\n );\n authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));\n SecurityContextHolder.getContext().setAuthentication(authToken);\n }\n }\n\n filterChain.doFilter(request, response);\n }\n}\n```\n\n**面试要点:**\n\n1. **OncePerRequestFilter**:确保每个请求只经过一次过滤器(避免转发/包含导致的重复过滤)\n2. **AntPathMatcher**:支持 Ant 风格路径匹配(`**`、`*`、`?` 通配符)\n3. **SecurityContextHolder**:使用 ThreadLocal 存储安全上下文,保证线程安全\n\n#### 2.3.3 RSA 前端加密传输\n\n为防止密码在传输过程中被截获,实现 RSA 非对称加密:\n\n**后端提供公钥:**\n\n```java\n@RestController\n@RequestMapping(\"/api/rsa\")\npublic class RsaController {\n\n private final RsaUtil rsaUtil;\n\n @GetMapping(\"/public-key\")\n public ApiResponse getPublicKey() {\n return ApiResponse.success(\"获取成功\", rsaUtil.getPublicKey());\n }\n}\n```\n\n**前端加密实现:**\n\n```javascript\nimport JSEncrypt from \"jsencrypt\";\n\nclass RsaEncryption {\n async initialize() {\n const response = await fetch(\"/api/rsa/public-key\");\n const data = await response.json();\n this.publicKey = data.data;\n }\n\n encrypt(text) {\n const encrypt = new JSEncrypt();\n encrypt.setPublicKey(this.publicKey);\n return encrypt.encrypt(text);\n }\n}\n```\n\n**安全流程:**\n\n1. 前端获取 RSA 公钥\n2. 用户密码使用公钥加密\n3. 后端使用私钥解密\n4. 解密后的密码再使用 BCrypt 加密存储\n\n### 2.4 数据库设计\n\n#### 2.4.1 核心实体关系\n\n```\n┌─────────────┐ 1:1 ┌─────────────┐\n│ User │─────────────▶│ Admin │\n└─────────────┘ └─────────────┘\n │\n │ 1:N\n ▼\n┌─────────────┐ N:1 ┌─────────────┐\n│ UserFile │◀─────────────│ UserFolder │\n└─────────────┘ └─────────────┘\n │\n │ 1:N\n ▼\n┌─────────────┐\n│ ChatRecord │\n└─────────────┘\n │\n │ N:1\n ▼\n┌─────────────┐\n│ ChatSession │\n└─────────────┘\n```\n\n#### 2.4.2 核心实体定义\n\n**用户实体 (User.java):**\n\n```java\n@Entity\n@Table(name = \"users\", indexes = {\n @Index(name = \"idx_email\", columnList = \"email\"),\n @Index(name = \"idx_username\", columnList = \"username\")\n})\n@EntityListeners(AuditingEntityListener.class)\n@Data\npublic class User {\n\n @Id\n @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n\n @Column(nullable = false, unique = true, length = 80)\n private String username;\n\n @Column(nullable = false, unique = true, length = 120)\n private String email;\n\n @Column(name = \"password_hash\", nullable = false, length = 255)\n private String passwordHash;\n\n @CreatedDate\n @Column(name = \"created_at\", updatable = false)\n private LocalDateTime createdAt;\n\n @LastModifiedDate\n @Column(name = \"updated_at\")\n private LocalDateTime updatedAt;\n\n @OneToOne(mappedBy = \"user\", cascade = CascadeType.ALL, orphanRemoval = true)\n private Admin admin;\n\n @OneToMany(mappedBy = \"user\", cascade = CascadeType.ALL, orphanRemoval = true)\n @JsonIgnore\n private List files = new ArrayList<>();\n\n public void setPassword(String password) {\n BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();\n this.passwordHash = encoder.encode(password);\n }\n\n public boolean checkPassword(String password) {\n BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();\n return encoder.matches(password, this.passwordHash);\n }\n}\n```\n\n**聊天记录实体 (ChatRecord.java):**\n\n```java\n@Entity\n@Table(name = \"chat_records\", indexes = {\n @Index(name = \"idx_user_id\", columnList = \"user_id\"),\n @Index(name = \"idx_session_id\", columnList = \"session_id\"),\n @Index(name = \"idx_user_session\", columnList = \"user_id, session_id\")\n})\n@Data\n@Builder\npublic class ChatRecord {\n\n @Id\n @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n\n @Column(name = \"user_id\")\n private Long userId;\n\n @Column(name = \"session_id\", nullable = false)\n private String sessionId;\n\n @Column(name = \"message_order\", nullable = false)\n private Integer messageOrder; // 消息顺序,用于排序\n\n @Column(name = \"sender_type\", nullable = false)\n private Integer senderType; // 1: 用户, 2: AI, 3: 工具结果\n\n @Column(columnDefinition = \"TEXT\")\n private String content;\n\n @Column(name = \"reasoning_content\", columnDefinition = \"TEXT\")\n private String reasoningContent; // AI 深度思考内容(推理模型)\n\n @Column(name = \"ai_model\", length = 50)\n private String aiModel; // deepseek, doubao, deepseek-reasoner\n\n @Column(name = \"status\", length = 20)\n private String status; // pending, completed, failed, cancelled\n\n @Column(name = \"send_time\")\n private LocalDateTime sendTime;\n}\n```\n\n**面试要点:**\n\n1. **索引设计**:`idx_user_session` 复合索引优化按用户+会话查询\n2. **实体监听器**:`@CreatedDate`、`@LastModifiedDate` 自动维护时间戳\n3. **级联操作**:`CascadeType.ALL` + `orphanRemoval = true` 实现级联删除\n\n### 2.5 AI 服务集成\n\n#### 2.5.1 多模型支持架构\n\n系统支持多个 AI 模型提供商,通过策略模式实现灵活切换:\n\n```java\n@Service\npublic class AiChatServiceImpl implements AiChatService {\n\n // Spring AI 自动注入的客户端\n private final ObjectProvider chatClientProvider;\n private final ObjectProvider streamingChatClientProvider;\n\n // 自定义模型客户端\n private ChatClient doubaoChatClient; // 豆包模型\n private ChatClient deepseekChatClient; // DeepSeek 模型\n private ChatClient deepseekReasonerClient; // DeepSeek 推理模型\n\n @Value(\"${ai.doubao.api-key:}\")\n private String doubaoApiKey;\n\n @Value(\"${ai.deepseek.api-url:}\")\n private String deepseekApiUrl;\n\n // 初始化各模型客户端\n public AiChatServiceImpl(...) {\n // 豆包模型初始化\n if (doubaoApiKey != null && !doubaoApiKey.isEmpty()) {\n OpenAiApi doubaoApi = new OpenAiApi(doubaoBaseUrl + \"/api/v3\", doubaoApiKey);\n OpenAiChatOptions doubaoOptions = OpenAiChatOptions.builder()\n .withModel(\"doubao-pro-32k\")\n .withTemperature(0.7f)\n .withMaxTokens(maxTokens)\n .build();\n this.doubaoChatClient = new OpenAiChatClient(doubaoApi, doubaoOptions);\n }\n\n // DeepSeek 模型初始化\n if (deepseekApiKey != null && !deepseekApiKey.isEmpty()) {\n OpenAiApi deepseekApi = new OpenAiApi(deepseekApiUrl, deepseekApiKey);\n this.deepseekChatClient = new OpenAiChatClient(deepseekApi);\n }\n }\n}\n```\n\n**面试要点:**\n\n1. **Spring AI 兼容性**:通过 OpenAI 兼容 API 接入国产模型(豆包、DeepSeek)\n2. **ObjectProvider 延迟注入**:避免循环依赖,按需获取 Bean\n3. **配置外部化**:API Key 和 URL 通过配置文件管理,支持环境变量覆盖\n\n#### 2.5.2 流式响应实现 (SSE)\n\n```java\n@Override\npublic SseEmitter askStream(String prompt, String sessionId, String model,\n Long userId, String ipAddress) {\n // 创建 SSE 发射器,超时 5 分钟\n SseEmitter emitter = new SseEmitter(300_000L);\n\n chatExecutor.execute(() -> {\n try {\n // 敏感信息脱敏\n String maskedPrompt = SensitiveDataMasker.mask(prompt);\n\n // 构建对话 Prompt(包含历史上下文)\n Prompt promptObj = buildPrompt(maskedPrompt, sessionId, userId, ...);\n\n // 流式调用 AI\n streamingChatClient.stream(promptObj)\n .doOnNext(chatResponse -> {\n String content = chatResponse.getResult().getOutput().getContent();\n if (content != null && !content.isEmpty()) {\n // 发送 SSE 事件\n Map result = new HashMap<>();\n result.put(\"content\", content);\n emitter.send(SseEmitter.event()\n .data(objectMapper.writeValueAsString(result))\n .name(\"message\"));\n }\n })\n .doOnError(e -> handleError(emitter, e))\n .blockLast();\n\n // 发送完成事件\n emitter.send(SseEmitter.event().data(\"[DONE]\"));\n emitter.complete();\n\n } catch (Exception e) {\n handleError(emitter, e);\n }\n });\n\n return emitter;\n}\n```\n\n**SSE (Server-Sent Events) 技术要点:**\n\n1. **单向通信**:服务器向客户端推送数据,适合 AI 流式输出场景\n2. **自动重连**:浏览器原生支持断线重连\n3. **相比 WebSocket**:更简单、更轻量,适合单向数据流\n\n#### 2.5.3 上下文管理策略\n\n```java\n@Value(\"${ai.context.max-history-messages:30}\")\nprivate Integer maxHistoryMessages; // 最大历史消息数\n\n@Value(\"${ai.context.max-history-chars:20000}\")\nprivate Integer maxHistoryChars; // 最大历史字符数\n\nprivate Prompt buildPrompt(String prompt, String sessionId, Long userId, ...) {\n List messages = new ArrayList<>();\n\n // 1. 添加系统提示词\n messages.add(new SystemMessage(systemPrompt));\n\n // 2. 加载历史对话(带预算控制)\n if (sessionId != null && userId != null) {\n int budget = maxHistoryChars;\n List history = chatRecordRepository\n .findByUserIdAndSessionIdOrderByMessageOrderDesc(userId, sessionId,\n PageRequest.of(0, maxHistoryMessages));\n\n for (ChatRecord record : history) {\n if (budget <= 0) break;\n String role = (record.getSenderType() == 1) ? \"user\" : \"assistant\";\n String content = truncateToMax(record.getContent(), budget);\n budget -= content.length();\n messages.add(0, new Message(role, content));\n }\n }\n\n // 3. 添加当前用户输入\n messages.add(new UserMessage(prompt));\n\n return new Prompt(messages);\n}\n```\n\n**上下文管理策略:**\n\n1. **消息数量限制**:防止上下文过长导致 Token 超限\n2. **字符预算控制**:动态计算可用空间,优先保留最近对话\n3. **敏感信息脱敏**:发送给 AI 前过滤身份证、手机号等隐私数据\n\n### 2.6 GraphQL API 设计\n\n#### 2.6.1 为什么选择 GraphQL?\n\n| 特性 | REST API | GraphQL |\n| -------- | ---------------- | ---------------------- |\n| 数据获取 | 固定返回结构 | 按需获取字段 |\n| 请求次数 | 可能需要多次请求 | 单次请求获取所有数据 |\n| 版本管理 | v1, v2... | 无需版本 |\n| 适合场景 | 简单 CRUD | 复杂数据关系、前端驱动 |\n\n#### 2.6.2 声明式数据分片加载\n\n```java\n@Controller\npublic class RequirementDocGraphQLController {\n\n /**\n * 查询需求文档列表(分页)\n * 前端可通过 Fragment 指定需要的字段\n */\n @QueryMapping\n public RequirementDocConnection requirementDocs(\n @Argument Integer page,\n @Argument Integer size,\n @AuthenticationPrincipal CustomUserDetails principal) {\n\n Page docPage = requirementDocRepository.findByUserId(\n principal.getUser().getId(),\n PageRequest.of(page, size)\n );\n return RequirementDocConnection.fromPage(docPage);\n }\n\n /**\n * 按需加载用户信息\n * 只有前端请求 user 字段时才执行\n */\n @SchemaMapping(typeName = \"RequirementDoc\", field = \"user\")\n public CompletableFuture user(RequirementDoc doc) {\n return CompletableFuture.supplyAsync(() ->\n userRepository.findById(doc.getUserId()).orElse(null)\n );\n }\n\n /**\n * 按需加载统计信息\n */\n @SchemaMapping(typeName = \"RequirementDoc\", field = \"statistics\")\n public RequirementDocStatistics statistics(RequirementDoc doc) {\n int wordCount = doc.getContent() != null ? doc.getContent().length() : 0;\n int editCount = historyRepository.countByDocId(doc.getId());\n return RequirementDocStatistics.builder()\n .wordCount(wordCount)\n .editCount(editCount)\n .build();\n }\n}\n```\n\n**前端查询示例:**\n\n```graphql\nquery {\n requirementDocs(page: 0, size: 10) {\n content {\n id\n title\n ...BasicFields # 只加载基础字段\n user {\n username\n avatar\n }\n }\n }\n}\n```\n\n### 2.7 PRD 需求文档流水线\n\n#### 2.7.1 流水线架构\n\n```\n用户输入想法\n │\n ▼\n┌─────────┐ ┌─────────┐ ┌─────────────┐\n│ Outline │───▶│ Draft │───▶│ Critique │◀──┐\n│ 大纲 │ │ 初稿 │ │ 评审 │ │\n└─────────┘ └─────────┘ └─────────────┘ │\n │ │\n ▼ │\n ┌───────────┐ │\n │ Revise │────┘\n │ 修订 │ (最多3轮)\n └───────────┘\n │\n ▼\n ┌───────────┐\n │ Complete │\n │ 完成 │\n └───────────┘\n```\n\n#### 2.7.2 流水线实现\n\n```java\n@Service\npublic class PrdPipelineServiceImpl implements PrdPipelineService {\n\n private static final int MAX_REVISIONS = 3;\n private static final String APPROVAL_PHRASE = \"No issues found.\";\n\n private static final String OUTLINE_PROMPT = \"\"\"\n You are a world-class product manager. Your task is to create a structured\n outline for a Product Requirements Document (PRD)...\n \"\"\";\n\n private static final String CRITIQUE_PROMPT = \"\"\"\n You are a meticulous and critical product manager...\n If the PRD is well-structured, respond with \"No issues found.\"\n \"\"\";\n\n @Async\n @Override\n public void runPipelineAsync(String runId, String idea, Long userId) {\n String content = \"# PRD for \" + idea;\n int revision = 0;\n\n try {\n // Step 1: 生成大纲\n sendState(runId, \"Outline\", content, revision, null);\n content = aiChatService.ask(String.format(OUTLINE_PROMPT, idea), ...);\n revision++;\n\n // Step 2: 生成初稿\n sendState(runId, \"Draft\", content, revision, null);\n content = aiChatService.ask(String.format(DRAFT_PROMPT, content), ...);\n revision++;\n\n // Step 3: 评审循环\n for (int i = 0; i < MAX_REVISIONS; i++) {\n sendState(runId, \"Critique\", content, revision, null);\n String critique = aiChatService.ask(String.format(CRITIQUE_PROMPT, content), ...);\n\n if (critique.contains(APPROVAL_PHRASE)) {\n break; // 通过评审\n }\n\n // 根据评审意见修订\n content = aiChatService.ask(String.format(REVISE_PROMPT, content, critique), ...);\n revision++;\n }\n\n sendState(runId, \"Complete\", content, revision, null);\n } catch (Exception e) {\n sendState(runId, \"Error\", content, revision + 1, null);\n }\n }\n}\n```\n\n**面试要点:**\n\n1. **@Async 异步执行**:避免长时间阻塞 HTTP 请求,通过 SSE 推送进度\n2. **评审循环**:最多 3 轮修订,确保文档质量\n3. **状态推送**:通过 PrdStreamHolder 实时推送流水线状态\n\n### 2.8 限流与审计\n\n#### 2.8.1 基于 Redis 的 IP 限流\n\n```java\n@Service\npublic class RateLimitService {\n\n private final StringRedisTemplate redisTemplate;\n\n private static final String KEY_PREFIX = \"chat_limit:\";\n private static final int MAX_REQUESTS = 5; // 每日最大请求次数\n private static final Duration EXPIRATION = Duration.ofHours(24);\n\n public boolean checkAndIncrement(String ip) {\n String key = KEY_PREFIX + ip;\n\n Long count = redisTemplate.opsForValue().increment(key);\n\n // 首次请求设置过期时间\n if (count != null && count == 1) {\n redisTemplate.expire(key, EXPIRATION);\n }\n\n if (count != null && count > MAX_REQUESTS) {\n log.warn(\"Rate limit exceeded for IP: {} (Count: {})\", ip, count);\n return false;\n }\n\n return true;\n }\n}\n```\n\n**限流算法:计数器算法**\n\n- 优点:实现简单,内存占用小\n- 缺点:存在临界问题(可在临界点突发请求)\n- 改进方案:滑动窗口、令牌桶、漏桶\n\n#### 2.8.2 Token 消耗审计\n\n```java\npublic interface TokenUsageAuditService {\n void record(String provider, String modelName, Long userId, String sessionId,\n Integer inputTokens, Integer outputTokens,\n long responseTimeMs, boolean streaming);\n}\n```\n\n记录每次 AI 调用的:\n\n- Token 消耗量(输入/输出)\n- 响应时间\n- 模型提供商\n- 用户/会话信息\n\n---\n\n## 三、前端架构详解 (vue-app)\n\n### 3.1 项目结构\n\n```\nvue-app/\n├── src/\n│ ├── components/ # 可复用组件\n│ │ ├── Sidebar/ # 侧边栏组件\n│ │ ├── AppHeader.vue # 头部组件\n│ │ └── RequirementManager.vue # PRD 管理组件\n│ ├── composables/ # 组合式函数 (Hooks)\n│ │ └── useGraphQLClient.js\n│ ├── config/ # 配置文件\n│ │ └── api.js # API 端点配置\n│ ├── stores/ # Pinia 状态管理\n│ │ ├── auth.js # 认证状态\n│ │ ├── chat.js # 聊天状态\n│ │ ├── cloudDisk.js # 云盘状态\n│ │ └── theme.js # 主题状态\n│ ├── utils/ # 工具函数\n│ │ ├── request.js # Axios 封装\n│ │ ├── rsaEncryption.js # RSA 加密\n│ │ └── graphqlClient.js # GraphQL 客户端\n│ ├── views/ # 页面视图\n│ │ ├── auth/ # 认证相关页面\n│ │ ├── ChatView.vue # AI 对话页面\n│ │ ├── CloudDiskView.vue # 云盘页面\n│ │ └── WordGameView.vue # 单词记忆入口\n│ ├── router/ # 路由配置\n│ │ └── index.js\n│ ├── App.vue # 根组件\n│ └── main.js # 入口文件\n├── vite.config.js # Vite 配置\n└── package.json\n```\n\n### 3.2 Vite 构建优化\n\n```javascript\nexport default defineConfig({\n plugins: [vue()],\n resolve: {\n alias: {\n \"@\": fileURLToPath(new URL(\"./src\", import.meta.url)),\n },\n },\n server: {\n port: 3000,\n proxy: {\n \"/api\": {\n target: \"http://localhost:5000\", // 代理到后端\n changeOrigin: true,\n },\n },\n },\n build: {\n outDir: \"dist\",\n sourcemap: false,\n rollupOptions: {\n output: {\n manualChunks: {\n \"vue-vendor\": [\"vue\", \"vue-router\", \"pinia\"], // Vue 全家桶\n highlight: [\"highlight.js\"], // 代码高亮\n markdown: [\"marked\"], // Markdown 解析\n },\n },\n },\n },\n});\n```\n\n**构建优化策略:**\n\n1. **代码分割 (Code Splitting)**:将第三方库分离,利用浏览器缓存\n2. **Tree Shaking**:Vite 基于 ES Module,自动移除未使用代码\n3. **开发代理**:避免 CORS 问题,统一 API 路径\n\n### 3.3 Pinia 状态管理\n\n#### 3.3.1 认证状态管理 (auth.js)\n\n```javascript\nimport { defineStore } from \"pinia\";\nimport { computed, ref } from \"vue\";\n\nexport const useAuthStore = defineStore(\"auth\", () => {\n // 状态\n const token = ref(localStorage.getItem(\"token\") || \"\");\n const userInfo = ref(JSON.parse(localStorage.getItem(\"userInfo\") || \"null\"));\n\n // 计算属性\n const isAuthenticated = computed(() => !!token.value);\n const isAdmin = computed(() => userInfo.value?.is_admin === true);\n\n // 登录方法\n async function login(email, password) {\n const response = await request.post(API_ENDPOINTS.auth.login, {\n email,\n password,\n });\n\n const accessToken = response?.data?.access_token;\n if (accessToken) {\n token.value = accessToken;\n userInfo.value = {\n id: response.data.user_id,\n email: response.data.email,\n username: response.data.username,\n is_admin: response.data.is_admin,\n };\n\n // 持久化存储\n localStorage.setItem(\"token\", token.value);\n localStorage.setItem(\"userInfo\", JSON.stringify(userInfo.value));\n\n return { success: true };\n }\n return { success: false };\n }\n\n // 退出登录\n function logout() {\n token.value = \"\";\n userInfo.value = null;\n localStorage.removeItem(\"token\");\n localStorage.removeItem(\"userInfo\");\n }\n\n return {\n token,\n userInfo,\n isAuthenticated,\n isAdmin,\n login,\n logout,\n };\n});\n```\n\n**Pinia vs Vuex 对比:**\n| 特性 | Vuex | Pinia |\n|------|------|-------|\n| 状态定义 | state 对象 | ref/reactive |\n| 修改方式 | mutations | 直接修改 |\n| TypeScript | 需要额外配置 | 原生支持 |\n| 模块化 | modules | 独立 Store |\n| DevTools | 支持 | 支持 |\n\n#### 3.3.2 聊天状态管理 (chat.js)\n\n```javascript\nexport const useChatStore = defineStore(\"chat\", () => {\n const sessions = ref([]);\n const currentSessionId = ref(null);\n const messages = ref([]);\n const isLoading = ref(false);\n const abortController = ref(null);\n const selectedModel = ref(localStorage.getItem(\"selectedModel\") || \"deepseek-chat\");\n\n // 流式发送消息\n async function sendMessage(content, onChunk) {\n isLoading.value = true;\n abortController.value = new AbortController();\n\n // 添加用户消息\n messages.value.push({\n role: \"user\",\n content,\n timestamp: new Date().toISOString(),\n });\n\n // 添加 AI 消息占位符\n const aiMessage = {\n role: \"assistant\",\n content: \"\",\n reasoning_content: \"\",\n isStreaming: true,\n timestamp: new Date().toISOString(),\n };\n messages.value.push(aiMessage);\n\n try {\n const response = await fetch(\"/api/ask-stream\", {\n method: \"POST\",\n signal: abortController.value.signal,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authStore.token}`,\n },\n body: JSON.stringify({\n prompt: content,\n session_id: currentSessionId.value,\n model: selectedModel.value,\n }),\n });\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"data:\")) {\n const data = line.slice(5).trim();\n if (data === \"[DONE]\") continue;\n\n const parsed = JSON.parse(data);\n\n // 处理推理内容\n if (parsed.reasoning_content) {\n aiMessage.reasoning_content += parsed.reasoning_content;\n }\n\n // 处理回复内容\n if (parsed.content) {\n aiMessage.content += parsed.content;\n }\n }\n }\n }\n\n aiMessage.isStreaming = false;\n return { success: true };\n } catch (error) {\n if (error.name === \"AbortError\") {\n console.log(\"Generation aborted by user\");\n return { success: true, aborted: true };\n }\n throw error;\n } finally {\n isLoading.value = false;\n }\n }\n\n // 停止生成\n function stopGeneration() {\n if (abortController.value) {\n abortController.value.abort();\n }\n }\n\n return {\n sessions,\n messages,\n isLoading,\n selectedModel,\n sendMessage,\n stopGeneration,\n };\n});\n```\n\n**SSE 客户端实现要点:**\n\n1. **ReadableStream API**:原生流式读取响应体\n2. **AbortController**:支持取消请求\n3. **增量更新**:逐字符追加内容,实现打字机效果\n\n### 3.4 前端安全措施\n\n1. **XSS 防护**:使用 DOMPurify 清理用户输入\n2. **密码加密**:RSA 非对称加密传输\n3. **Token 存储**:localStorage + XSS 风险权衡\n4. **CORS 配置**:后端白名单控制\n\n---\n\n## 四、单词记忆模块 (word-game)\n\n### 4.1 技术架构\n\n```\nword-game/\n├── server/ # Node.js 后端\n│ ├── index.js # Express 服务入口\n│ └── progress.db # SQLite 数据库\n├── src/ # Vue 3 前端\n│ ├── components/\n│ │ ├── game/ # 游戏组件\n│ │ │ ├── AnswerView.vue\n│ │ │ ├── TypingInput.vue\n│ │ │ └── CompletionModal.vue\n│ │ └── pages/ # 页面组件\n│ ├── composables/ # 组合式函数\n│ │ ├── useEnglishSound.ts # 发音功能\n│ │ └── useQuestion.ts # 题目逻辑\n│ ├── stores/ # Pinia 状态\n│ │ ├── courseStore.ts\n│ │ └── progressStore.ts\n│ └── services/\n│ └── wordGameApi.ts # API 封装\n└── vite.config.ts\n```\n\n### 4.2 后端实现 (Express 5 + SQLite)\n\n#### 4.2.1 数据库设计\n\n```javascript\nconst db = new Database(join(__dirname, \"progress.db\"));\ndb.pragma(\"journal_mode = WAL\"); // Write-Ahead Logging 提升并发性能\n\ndb.exec(`\n -- 用户学习进度表\n CREATE TABLE IF NOT EXISTS course_progress (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n user_key TEXT NOT NULL, -- 用户标识(userId 或 guest_IP)\n user_type TEXT NOT NULL DEFAULT 'guest',\n package_id TEXT NOT NULL, -- 课程包 ID\n course_index INTEGER NOT NULL, -- 课程索引\n current_q INTEGER NOT NULL DEFAULT 0, -- 当前题目\n completed INTEGER NOT NULL DEFAULT 0, -- 是否完成\n study_secs INTEGER NOT NULL DEFAULT 0, -- 学习时长\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n UNIQUE(user_key, package_id, course_index)\n );\n\n -- 用户自定义课程包\n CREATE TABLE IF NOT EXISTS user_packages (\n id TEXT PRIMARY KEY,\n user_key TEXT NOT NULL,\n name TEXT NOT NULL,\n description TEXT NOT NULL DEFAULT '',\n icon TEXT NOT NULL DEFAULT '📦',\n is_public INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n -- 课程包题目\n CREATE TABLE IF NOT EXISTS user_package_statements (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n package_id TEXT NOT NULL,\n course_index INTEGER NOT NULL DEFAULT 0,\n english TEXT NOT NULL,\n chinese TEXT NOT NULL,\n soundmark TEXT NOT NULL DEFAULT ''\n );\n`);\n```\n\n**SQLite 优势:**\n\n1. **零配置**:无需独立数据库服务\n2. **单文件存储**:便于备份和迁移\n3. **WAL 模式**:提升并发读写性能\n4. **适合场景**:嵌入式应用、小型项目、开发测试\n\n#### 4.2.2 JWT 认证中间件\n\n```javascript\n/**\n * 与主站共享 JWT 密钥,实现单点登录\n */\nfunction requireAispringAuth(req, res, next) {\n try {\n const auth = req.headers[\"authorization\"];\n if (!auth || !auth.startsWith(\"Bearer \")) {\n return res.status(401).json({ success: false, message: \"未登录\" });\n }\n\n const token = auth.slice(7);\n const key = getJwtSigningKey(); // 与主站一致的密钥\n\n jwt.verify(token, key, { algorithms: [\"HS256\"] });\n next();\n } catch (err) {\n const msg = err.name === \"TokenExpiredError\" ? \"登录已过期\" : \"无效的登录凭证\";\n res.status(401).json({ success: false, message: msg });\n }\n}\n\n// 应用中间件\napp.use(\"/api\", requireAispringAuth);\n```\n\n#### 4.2.3 核心路由\n\n```javascript\n// 获取课程包列表(支持搜索、按点击量排序)\napp.get(\"/api/packages\", (req, res) => {\n const { key } = resolveUserKey(req);\n const search = req.query.search;\n\n let list = [...PACKAGES]; // 内置课程包\n const userRows = getUserPackagesList(key, search);\n list.push(...userRows.map(userPackageToMeta));\n\n // 按点击量排序\n list.sort((a, b) => (b.clickCount || 0) - (a.clickCount || 0));\n\n res.json({ success: true, data: list });\n});\n\n// 获取课程题目\napp.get(\"/api/courses/:courseIndex/questions\", (req, res) => {\n const packageId = req.query.packageId;\n const idx = parseInt(req.params.courseIndex, 10);\n\n if (packageId && packageId.startsWith(\"up-\")) {\n // 用户自定义课程包\n const rows = db.prepare(`\n SELECT english, chinese, soundmark\n FROM user_package_statements\n WHERE package_id = ? AND course_index = ?\n ORDER BY sort_order, id\n `).all(packageId, idx - 1);\n return res.json({ success: true, data: rows });\n }\n\n // 内置课程包\n const filePath = join(COURSES_DIR, `${String(idx).padStart(2, \"0\")}.json`);\n const statements = JSON.parse(readFileSync(filePath, \"utf-8\"));\n res.json({ success: true, data: statements });\n});\n\n// 创建自定义课程包\napp.post(\"/api/packages\", (req, res) => {\n const { key } = resolveUserKey(req);\n const { name, description, sections, isPublic } = req.body;\n\n const packageId = \"up-\" + randomUUID().replace(/-/g, \"\").slice(0, 16);\n\n db.transaction(() => {\n // 插入课程包元数据\n db.prepare(`INSERT INTO user_packages ...`).run(packageId, key, name, ...);\n\n // 插入各节题目\n for (const section of sections) {\n for (const stmt of section.statements) {\n db.prepare(`INSERT INTO user_package_statements ...`).run(...);\n }\n }\n })();\n\n res.status(201).json({ success: true, data: { id: packageId } });\n});\n```\n\n### 4.3 前端实现\n\n#### 4.3.1 打字输入组件\n\n```vue\n\n\n\n```\n\n#### 4.3.2 发音功能实现\n\n```typescript\nexport function useEnglishSound() {\n const audioContext = new (window.AudioContext || window.webkitAudioContext)()\n\n async function play(text: string) {\n // 使用 Web Speech API\n const utterance = new SpeechSynthesisUtterance(text)\n utterance.lang = 'en-US'\n utterance.rate = 0.9\n speechSynthesis.speak(utterance)\n }\n\n return { play }\n}\n```\n\n### 4.4 iframe 跨域通信\n\n主站通过 iframe 嵌入单词记忆模块,使用 postMessage 实现通信:\n\n```vue\n\n\n\n\n```\n\n---\n\n## 五、部署架构\n\n### 5.1 生产环境部署\n\n```\n ┌─────────────────────────────────────┐\n │ Nginx (反向代理) │\n │ Port: 80 / 443 │\n └─────────────────────────────────────┘\n │\n ┌───────────────────────────┼───────────────────────────┐\n │ │ │\n ▼ ▼ ▼\n┌───────────────┐ ┌───────────────┐ ┌───────────────┐\n│ aistudy.icu │ │ earthworm. │ │ 静态资源 │\n│ (主站) │ │ aistudy.icu │ │ (CDN) │\n│ → :5000 │ │ → :5201 │ │ │\n└───────────────┘ └───────────────┘ └───────────────┘\n │ │\n ▼ ▼\n┌───────────────┐ ┌───────────────┐\n│ Spring Boot │ │ Node.js │\n│ JAR / Docker │ │ Express │\n└───────────────┘ └───────────────┘\n │ │\n └───────────┬───────────────┘\n ▼\n ┌───────────────────────┐\n │ MySQL 8.x │\n │ Redis 7.x │\n └───────────────────────┘\n```\n\n### 5.2 Nginx 配置示例\n\n```nginx\n# 主站\nserver {\n listen 80;\n server_name aistudy.icu;\n\n location / {\n proxy_pass http://127.0.0.1:5000;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n\n # SSE 支持\n proxy_http_version 1.1;\n proxy_set_header Connection '';\n proxy_buffering off;\n proxy_cache off;\n proxy_read_timeout 300s;\n }\n}\n\n# 单词记忆模块\nserver {\n listen 80;\n server_name earthworm.aistudy.icu;\n\n location / {\n proxy_pass http://127.0.0.1:5201;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n }\n}\n```\n\n---\n\n## 六、性能优化总结\n\n### 6.1 后端优化\n\n| 优化点 | 实现方式 | 效果 |\n| ---------- | ------------------ | ---------------- |\n| 数据库索引 | 复合索引、覆盖索引 | 查询性能提升 10x |\n| 连接池 | HikariCP 默认配置 | 减少连接创建开销 |\n| 异步处理 | @Async + 线程池 | 非阻塞响应 |\n| 缓存策略 | Redis + 本地缓存 | 减少数据库压力 |\n| 流式响应 | SSE | 首字节时间优化 |\n\n### 6.2 前端优化\n\n| 优化点 | 实现方式 | 效果 |\n| -------- | -------------------- | ---------------- |\n| 代码分割 | manualChunks | 首屏加载减少 60% |\n| 懒加载 | 路由懒加载 | 按需加载页面 |\n| 虚拟滚动 | vue-virtual-scroller | 大列表性能优化 |\n| 防抖节流 | lodash | 减少无效请求 |\n| 缓存策略 | localStorage | 减少网络请求 |\n\n---\n\n## 七、面试高频问题\n\n### Q1: 为什么选择 Spring Boot 3.x?\n\n**回答要点:**\n\n1. 要求 Java 17+,支持 Virtual Threads(虚拟线程),大幅提升并发性能\n2. 原生支持 GraalVM 编译为原生可执行文件,启动时间从秒级降到毫秒级\n3. ProblemDetail API 标准化错误响应\n4. 可观测性增强(Micrometer Tracing)\n\n### Q2: JWT Token 如何实现续期?\n\n**回答要点:**\n\n1. **短期 Token + Refresh Token**:Access Token 有效期短(如 30 分钟),Refresh Token 有效期长(如 7 天)\n2. **滑动过期**:每次请求检查 Token 剩余有效期,若低于阈值则生成新 Token 返回\n3. **本项目方案**:Token 有效期 24 小时,过期后需重新登录\n\n### Q3: 如何防止 XSS 攻击?\n\n**回答要点:**\n\n1. **输入过滤**:使用 DOMPurify 清理用户输入\n2. **输出编码**:Vue 自动转义插值表达式\n3. **CSP 策略**:Content-Security-Policy 头限制脚本来源\n4. **HttpOnly Cookie**:敏感 Cookie 不允许 JS 访问(本项目使用 localStorage,需权衡)\n\n### Q4: SSE 和 WebSocket 如何选择?\n\n| 特性 | SSE | WebSocket |\n| -------- | --------------------- | -------------- |\n| 通信方向 | 单向(服务器→客户端) | 双向 |\n| 协议 | HTTP | WS/WSS |\n| 重连 | 浏览器自动重连 | 需手动实现 |\n| 适用场景 | 推送通知、AI 流式输出 | 实时聊天、游戏 |\n\n**本项目选择 SSE 的原因**:AI 对话场景只需服务器向客户端推送数据,SSE 更简单、更轻量。\n\n### Q5: 如何保证数据库与缓存一致性?\n\n**回答要点:**\n\n1. **Cache-Aside 模式**:先更新数据库,再删除缓存\n2. **延迟双删**:删除缓存 → 更新数据库 → 延迟再删除缓存\n3. **消息队列**:通过消息队列保证最终一致性\n4. **本项目方案**:写操作直接更新数据库,读操作先查缓存再查数据库\n\n---\n\n## 八、技术亮点总结\n\n1. **多模型 AI 集成**:通过 Spring AI 统一抽象层,支持 DeepSeek、豆包等多个模型\n2. **流式响应优化**:SSE 实现打字机效果,提升用户体验\n3. **GraphQL 按需加载**:解决 REST API 过度获取/获取不足问题\n4. **PRD 流水线**:多阶段 AI 协作,自动生成需求文档\n5. **微前端架构**:iframe + postMessage 实现模块解耦\n6. **安全加固**:RSA 加密传输 + JWT 认证 + 限流防护\n\n---\n\n_文档版本: 2.0_ \n_最后更新: 2026-02-28_\n"}, "66d582c2643956640599f78c65bed8d6caee84d5": {"t": 1785766000.222989, "n": 41965, "h": "fcfb48007809378c", "c": "# AI智能学习助手系统 - 技术架构详解\n\n> 本文档详细记录系统的技术实现细节,涵盖架构设计、核心模块实现、安全机制、性能优化等方面,可作为面试技术深度的参考材料。\n\n---\n\n## 一、系统架构概览\n\n### 1.1 整体架构设计\n\n本系统采用**前后端分离 + 微服务化**的架构模式,由三个核心子系统组成:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│ 用户层 (Browser) │\n└─────────────────────────────────────────────────────────────────────────┘\n │\n ┌───────────────┼───────────────┐\n ▼ ▼ ▼\n ┌──────────────┐ ┌──────────────┐ ┌──────────────┐\n │ vue-app │ │ word-game │ │ Nginx │\n │ (Vue 3) │ │ (Vue 3) │ │ 反向代理 │\n │ Port: 3000 │ │ Port: 5200 │ │ │\n └──────────────┘ └──────────────┘ └──────────────┘\n │ │\n └───────┬───────┘\n ▼\n ┌──────────────────────────────┐\n │ aispring 后端 │\n │ (Spring Boot 3.3.5) │\n │ Port: 5000 │\n └──────────────────────────────┘\n │\n ┌───────────────┼───────────────┐\n ▼ ▼ ▼\n ┌──────────────┐ ┌──────────────┐ ┌──────────────┐\n │ MySQL │ │ Redis │ │ AI Services │\n │ (主数据库) │ │ (缓存/限流) │ │ DeepSeek/豆包 │\n └──────────────┘ └──────────────┘ └──────────────┘\n │\n ▼\n ┌──────────────────────────────┐\n │ word-game-server │\n │ (Express 5 + SQLite) │\n │ Port: 5201 │\n └──────────────────────────────┘\n```\n\n### 1.2 技术栈总览\n\n| 层级 | 技术选型 | 版本 | 选型理由 |\n| -------------- | --------------------- | ------ | ----------------------------------------------- |\n| **后端框架** | Spring Boot | 3.3.5 | 企业级Java框架,生态完善,支持响应式编程 |\n| **前端框架** | Vue 3 | 3.4.0 | Composition API,更好的TypeScript支持,性能优化 |\n| **构建工具** | Vite | 5.0.0 | ES Module原生支持,HMR速度快,打包体积小 |\n| **状态管理** | Pinia | 2.1.7 | Vue官方推荐,TypeScript友好,模块化设计 |\n| **数据库** | MySQL | 8.x | 关系型数据库,支持复杂查询和事务 |\n| **缓存** | Redis | 7.x | 高性能内存数据库,支持限流、会话管理 |\n| **ORM** | Spring Data JPA | 3.x | 简化数据访问层开发,支持方法命名查询 |\n| **认证** | JWT + Spring Security | 0.12.3 | 无状态认证,支持分布式部署 |\n| **AI集成** | Spring AI | 0.8.1 | 官方AI集成框架,统一API调用方式 |\n| **数据库迁移** | Flyway | 9.x | 版本化数据库变更管理 |\n\n---\n\n## 二、后端架构详解 (aispring)\n\n### 2.1 项目结构\n\n```\naispring/\n├── src/main/java/com/aispring/\n│ ├── config/ # 配置类\n│ │ ├── SecurityConfig.java # Spring Security 安全配置\n│ │ ├── RedisConfig.java # Redis 缓存配置\n│ │ ├── CorsConfig.java # 跨域配置\n│ │ ├── JacksonConfig.java # JSON 序列化配置\n│ │ └── StorageProperties.java # 文件存储配置\n│ ├── controller/ # 控制器层 (REST API)\n│ │ ├── AuthController.java # 认证相关\n│ │ ├── AiChatController.java # AI 对话\n│ │ ├── CloudDiskController.java # 云盘管理\n│ │ └── ...\n│ ├── service/ # 服务层 (业务逻辑)\n│ │ ├── impl/ # 服务实现\n│ │ ├── AiChatService.java\n│ │ ├── AuthService.java\n│ │ └── ...\n│ ├── repository/ # 数据访问层 (JPA)\n│ ├── entity/ # 实体类\n│ ├── dto/ # 数据传输对象\n│ │ ├── request/ # 请求DTO\n│ │ └── response/ # 响应DTO\n│ ├── security/ # 安全相关\n│ │ ├── JwtAuthenticationFilter.java\n│ │ ├── CustomUserDetails.java\n│ │ └── UserDetailsServiceImpl.java\n│ ├── graphql/ # GraphQL 支持\n│ └── exception/ # 异常处理\n├── migrations/ # Flyway 数据库迁移脚本\n└── pom.xml # Maven 依赖配置\n```\n\n### 2.2 核心依赖分析 (pom.xml)\n\n```xml\n\n\n org.springframework.boot\n spring-boot-starter-web\n\n\n\n\n org.springframework.boot\n spring-boot-starter-data-jpa\n\n\n\n\n org.springframework.boot\n spring-boot-starter-security\n\n\n\n\n io.jsonwebtoken\n jjwt-api\n 0.12.3\n\n\n\n\n org.springframework.ai\n spring-ai-openai-spring-boot-starter\n 0.8.1\n\n\n\n\n org.springframework.boot\n spring-boot-starter-graphql\n\n\n\n\n org.springframework.boot\n spring-boot-starter-data-redis\n\n\n\n\n org.flywaydb\n flyway-core\n\n```\n\n**技术选型关键点:**\n\n- **Spring Boot 3.x** 要求 **Java 17+**,支持 Virtual Threads(虚拟线程)\n- **Spring AI 0.8.1** 提供统一的 AI 模型调用抽象层,支持 OpenAI 兼容 API\n- **JJWT 0.12.3** 支持 JWT 的创建、解析和验证,支持多种签名算法\n\n### 2.3 安全架构设计\n\n#### 2.3.1 Spring Security 配置\n\n```java\n@Configuration\n@EnableWebSecurity\n@EnableMethodSecurity\n@RequiredArgsConstructor\npublic class SecurityConfig {\n\n private final JwtAuthenticationFilter jwtAuthFilter;\n\n @Bean\n public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n http\n .csrf(csrf -> csrf.disable()) // 禁用 CSRF(前后端分离架构)\n .cors(cors -> {}) // 启用 CORS\n .authorizeHttpRequests(auth -> auth\n // OPTIONS 预检请求放行\n .requestMatchers(HttpMethod.OPTIONS, \"/**\").permitAll()\n // SSE 异步分发放行\n .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()\n // 公开端点\n .requestMatchers(\"/api/auth/**\").permitAll()\n .requestMatchers(\"/api/ask\", \"/api/ask-stream\").permitAll()\n // 其他需要认证\n .anyRequest().authenticated()\n )\n .sessionManagement(session -> session\n .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话\n )\n .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);\n\n return http.build();\n }\n\n @Bean\n public PasswordEncoder passwordEncoder() {\n return new BCryptPasswordEncoder(); // BCrypt 密码加密\n }\n}\n```\n\n**面试要点:**\n\n1. **为什么禁用 CSRF?** 前后端分离架构,使用 JWT Token 认证,不依赖 Cookie-Session 机制\n2. **无状态会话的意义**:服务端不存储会话信息,便于水平扩展和负载均衡\n3. **BCrypt 加密优势**:自动加盐、计算成本可调、抗彩虹表攻击\n\n#### 2.3.2 JWT 认证过滤器\n\n```java\n@Component\n@RequiredArgsConstructor\npublic class JwtAuthenticationFilter extends OncePerRequestFilter {\n\n private final JwtUtil jwtUtil;\n private final UserDetailsService userDetailsService;\n\n private static final String[] PUBLIC_PATTERNS = {\n \"/api/auth/**\", \"/swagger-ui/**\", \"/api/public-files/**\"\n };\n\n private final AntPathMatcher pathMatcher = new AntPathMatcher();\n\n @Override\n protected boolean shouldNotFilter(HttpServletRequest request) {\n // OPTIONS 请求和公开路径跳过过滤\n if (\"OPTIONS\".equalsIgnoreCase(request.getMethod())) return true;\n\n String path = request.getServletPath();\n for (String pattern : PUBLIC_PATTERNS) {\n if (pathMatcher.match(pattern, path)) return true;\n }\n return false;\n }\n\n @Override\n protected void doFilterInternal(HttpServletRequest request,\n HttpServletResponse response,\n FilterChain filterChain) {\n final String authHeader = request.getHeader(\"Authorization\");\n\n if (authHeader == null || !authHeader.startsWith(\"Bearer \")) {\n filterChain.doFilter(request, response);\n return;\n }\n\n final String jwt = authHeader.substring(7);\n final String userEmail = jwtUtil.extractUsername(jwt);\n\n if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {\n UserDetails userDetails = userDetailsService.loadUserByUsername(userEmail);\n\n if (jwtUtil.isTokenValid(jwt, userDetails)) {\n UsernamePasswordAuthenticationToken authToken =\n new UsernamePasswordAuthenticationToken(\n userDetails, null, userDetails.getAuthorities()\n );\n authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));\n SecurityContextHolder.getContext().setAuthentication(authToken);\n }\n }\n\n filterChain.doFilter(request, response);\n }\n}\n```\n\n**面试要点:**\n\n1. **OncePerRequestFilter**:确保每个请求只经过一次过滤器(避免转发/包含导致的重复过滤)\n2. **AntPathMatcher**:支持 Ant 风格路径匹配(`**`、`*`、`?` 通配符)\n3. **SecurityContextHolder**:使用 ThreadLocal 存储安全上下文,保证线程安全\n\n#### 2.3.3 RSA 前端加密传输\n\n为防止密码在传输过程中被截获,实现 RSA 非对称加密:\n\n**后端提供公钥:**\n\n```java\n@RestController\n@RequestMapping(\"/api/rsa\")\npublic class RsaController {\n\n private final RsaUtil rsaUtil;\n\n @GetMapping(\"/public-key\")\n public ApiResponse getPublicKey() {\n return ApiResponse.success(\"获取成功\", rsaUtil.getPublicKey());\n }\n}\n```\n\n**前端加密实现:**\n\n```javascript\nimport JSEncrypt from \"jsencrypt\";\n\nclass RsaEncryption {\n async initialize() {\n const response = await fetch(\"/api/rsa/public-key\");\n const data = await response.json();\n this.publicKey = data.data;\n }\n\n encrypt(text) {\n const encrypt = new JSEncrypt();\n encrypt.setPublicKey(this.publicKey);\n return encrypt.encrypt(text);\n }\n}\n```\n\n**安全流程:**\n\n1. 前端获取 RSA 公钥\n2. 用户密码使用公钥加密\n3. 后端使用私钥解密\n4. 解密后的密码再使用 BCrypt 加密存储\n\n### 2.4 数据库设计\n\n#### 2.4.1 核心实体关系\n\n```\n┌─────────────┐ 1:1 ┌─────────────┐\n│ User │─────────────▶│ Admin │\n└─────────────┘ └─────────────┘\n │\n │ 1:N\n ▼\n┌─────────────┐ N:1 ┌─────────────┐\n│ UserFile │◀─────────────│ UserFolder │\n└─────────────┘ └─────────────┘\n │\n │ 1:N\n ▼\n┌─────────────┐\n│ ChatRecord │\n└─────────────┘\n │\n │ N:1\n ▼\n┌─────────────┐\n│ ChatSession │\n└─────────────┘\n```\n\n#### 2.4.2 核心实体定义\n\n**用户实体 (User.java):**\n\n```java\n@Entity\n@Table(name = \"users\", indexes = {\n @Index(name = \"idx_email\", columnList = \"email\"),\n @Index(name = \"idx_username\", columnList = \"username\")\n})\n@EntityListeners(AuditingEntityListener.class)\n@Data\npublic class User {\n\n @Id\n @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n\n @Column(nullable = false, unique = true, length = 80)\n private String username;\n\n @Column(nullable = false, unique = true, length = 120)\n private String email;\n\n @Column(name = \"password_hash\", nullable = false, length = 255)\n private String passwordHash;\n\n @CreatedDate\n @Column(name = \"created_at\", updatable = false)\n private LocalDateTime createdAt;\n\n @LastModifiedDate\n @Column(name = \"updated_at\")\n private LocalDateTime updatedAt;\n\n @OneToOne(mappedBy = \"user\", cascade = CascadeType.ALL, orphanRemoval = true)\n private Admin admin;\n\n @OneToMany(mappedBy = \"user\", cascade = CascadeType.ALL, orphanRemoval = true)\n @JsonIgnore\n private List files = new ArrayList<>();\n\n public void setPassword(String password) {\n BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();\n this.passwordHash = encoder.encode(password);\n }\n\n public boolean checkPassword(String password) {\n BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();\n return encoder.matches(password, this.passwordHash);\n }\n}\n```\n\n**聊天记录实体 (ChatRecord.java):**\n\n```java\n@Entity\n@Table(name = \"chat_records\", indexes = {\n @Index(name = \"idx_user_id\", columnList = \"user_id\"),\n @Index(name = \"idx_session_id\", columnList = \"session_id\"),\n @Index(name = \"idx_user_session\", columnList = \"user_id, session_id\")\n})\n@Data\n@Builder\npublic class ChatRecord {\n\n @Id\n @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n\n @Column(name = \"user_id\")\n private Long userId;\n\n @Column(name = \"session_id\", nullable = false)\n private String sessionId;\n\n @Column(name = \"message_order\", nullable = false)\n private Integer messageOrder; // 消息顺序,用于排序\n\n @Column(name = \"sender_type\", nullable = false)\n private Integer senderType; // 1: 用户, 2: AI, 3: 工具结果\n\n @Column(columnDefinition = \"TEXT\")\n private String content;\n\n @Column(name = \"reasoning_content\", columnDefinition = \"TEXT\")\n private String reasoningContent; // AI 深度思考内容(推理模型)\n\n @Column(name = \"ai_model\", length = 50)\n private String aiModel; // deepseek, doubao, deepseek-reasoner\n\n @Column(name = \"status\", length = 20)\n private String status; // pending, completed, failed, cancelled\n\n @Column(name = \"send_time\")\n private LocalDateTime sendTime;\n}\n```\n\n**面试要点:**\n\n1. **索引设计**:`idx_user_session` 复合索引优化按用户+会话查询\n2. **实体监听器**:`@CreatedDate`、`@LastModifiedDate` 自动维护时间戳\n3. **级联操作**:`CascadeType.ALL` + `orphanRemoval = true` 实现级联删除\n\n### 2.5 AI 服务集成\n\n#### 2.5.1 多模型支持架构\n\n系统支持多个 AI 模型提供商,通过策略模式实现灵活切换:\n\n```java\n@Service\npublic class AiChatServiceImpl implements AiChatService {\n\n // Spring AI 自动注入的客户端\n private final ObjectProvider chatClientProvider;\n private final ObjectProvider streamingChatClientProvider;\n\n // 自定义模型客户端\n private ChatClient doubaoChatClient; // 豆包模型\n private ChatClient deepseekChatClient; // DeepSeek 模型\n private ChatClient deepseekReasonerClient; // DeepSeek 推理模型\n\n @Value(\"${ai.doubao.api-key:}\")\n private String doubaoApiKey;\n\n @Value(\"${ai.deepseek.api-url:}\")\n private String deepseekApiUrl;\n\n // 初始化各模型客户端\n public AiChatServiceImpl(...) {\n // 豆包模型初始化\n if (doubaoApiKey != null && !doubaoApiKey.isEmpty()) {\n OpenAiApi doubaoApi = new OpenAiApi(doubaoBaseUrl + \"/api/v3\", doubaoApiKey);\n OpenAiChatOptions doubaoOptions = OpenAiChatOptions.builder()\n .withModel(\"doubao-pro-32k\")\n .withTemperature(0.7f)\n .withMaxTokens(maxTokens)\n .build();\n this.doubaoChatClient = new OpenAiChatClient(doubaoApi, doubaoOptions);\n }\n\n // DeepSeek 模型初始化\n if (deepseekApiKey != null && !deepseekApiKey.isEmpty()) {\n OpenAiApi deepseekApi = new OpenAiApi(deepseekApiUrl, deepseekApiKey);\n this.deepseekChatClient = new OpenAiChatClient(deepseekApi);\n }\n }\n}\n```\n\n**面试要点:**\n\n1. **Spring AI 兼容性**:通过 OpenAI 兼容 API 接入国产模型(豆包、DeepSeek)\n2. **ObjectProvider 延迟注入**:避免循环依赖,按需获取 Bean\n3. **配置外部化**:API Key 和 URL 通过配置文件管理,支持环境变量覆盖\n\n#### 2.5.2 流式响应实现 (SSE)\n\n```java\n@Override\npublic SseEmitter askStream(String prompt, String sessionId, String model,\n Long userId, String ipAddress) {\n // 创建 SSE 发射器,超时 5 分钟\n SseEmitter emitter = new SseEmitter(300_000L);\n\n chatExecutor.execute(() -> {\n try {\n // 敏感信息脱敏\n String maskedPrompt = SensitiveDataMasker.mask(prompt);\n\n // 构建对话 Prompt(包含历史上下文)\n Prompt promptObj = buildPrompt(maskedPrompt, sessionId, userId, ...);\n\n // 流式调用 AI\n streamingChatClient.stream(promptObj)\n .doOnNext(chatResponse -> {\n String content = chatResponse.getResult().getOutput().getContent();\n if (content != null && !content.isEmpty()) {\n // 发送 SSE 事件\n Map result = new HashMap<>();\n result.put(\"content\", content);\n emitter.send(SseEmitter.event()\n .data(objectMapper.writeValueAsString(result))\n .name(\"message\"));\n }\n })\n .doOnError(e -> handleError(emitter, e))\n .blockLast();\n\n // 发送完成事件\n emitter.send(SseEmitter.event().data(\"[DONE]\"));\n emitter.complete();\n\n } catch (Exception e) {\n handleError(emitter, e);\n }\n });\n\n return emitter;\n}\n```\n\n**SSE (Server-Sent Events) 技术要点:**\n\n1. **单向通信**:服务器向客户端推送数据,适合 AI 流式输出场景\n2. **自动重连**:浏览器原生支持断线重连\n3. **相比 WebSocket**:更简单、更轻量,适合单向数据流\n\n#### 2.5.3 上下文管理策略\n\n```java\n@Value(\"${ai.context.max-history-messages:30}\")\nprivate Integer maxHistoryMessages; // 最大历史消息数\n\n@Value(\"${ai.context.max-history-chars:20000}\")\nprivate Integer maxHistoryChars; // 最大历史字符数\n\nprivate Prompt buildPrompt(String prompt, String sessionId, Long userId, ...) {\n List messages = new ArrayList<>();\n\n // 1. 添加系统提示词\n messages.add(new SystemMessage(systemPrompt));\n\n // 2. 加载历史对话(带预算控制)\n if (sessionId != null && userId != null) {\n int budget = maxHistoryChars;\n List history = chatRecordRepository\n .findByUserIdAndSessionIdOrderByMessageOrderDesc(userId, sessionId,\n PageRequest.of(0, maxHistoryMessages));\n\n for (ChatRecord record : history) {\n if (budget <= 0) break;\n String role = (record.getSenderType() == 1) ? \"user\" : \"assistant\";\n String content = truncateToMax(record.getContent(), budget);\n budget -= content.length();\n messages.add(0, new Message(role, content));\n }\n }\n\n // 3. 添加当前用户输入\n messages.add(new UserMessage(prompt));\n\n return new Prompt(messages);\n}\n```\n\n**上下文管理策略:**\n\n1. **消息数量限制**:防止上下文过长导致 Token 超限\n2. **字符预算控制**:动态计算可用空间,优先保留最近对话\n3. **敏感信息脱敏**:发送给 AI 前过滤身份证、手机号等隐私数据\n\n### 2.6 GraphQL API 设计\n\n#### 2.6.1 为什么选择 GraphQL?\n\n| 特性 | REST API | GraphQL |\n| -------- | ---------------- | ---------------------- |\n| 数据获取 | 固定返回结构 | 按需获取字段 |\n| 请求次数 | 可能需要多次请求 | 单次请求获取所有数据 |\n| 版本管理 | v1, v2... | 无需版本 |\n| 适合场景 | 简单 CRUD | 复杂数据关系、前端驱动 |\n\n#### 2.6.2 声明式数据分片加载\n\n```java\n@Controller\npublic class RequirementDocGraphQLController {\n\n /**\n * 查询需求文档列表(分页)\n * 前端可通过 Fragment 指定需要的字段\n */\n @QueryMapping\n public RequirementDocConnection requirementDocs(\n @Argument Integer page,\n @Argument Integer size,\n @AuthenticationPrincipal CustomUserDetails principal) {\n\n Page docPage = requirementDocRepository.findByUserId(\n principal.getUser().getId(),\n PageRequest.of(page, size)\n );\n return RequirementDocConnection.fromPage(docPage);\n }\n\n /**\n * 按需加载用户信息\n * 只有前端请求 user 字段时才执行\n */\n @SchemaMapping(typeName = \"RequirementDoc\", field = \"user\")\n public CompletableFuture user(RequirementDoc doc) {\n return CompletableFuture.supplyAsync(() ->\n userRepository.findById(doc.getUserId()).orElse(null)\n );\n }\n\n /**\n * 按需加载统计信息\n */\n @SchemaMapping(typeName = \"RequirementDoc\", field = \"statistics\")\n public RequirementDocStatistics statistics(RequirementDoc doc) {\n int wordCount = doc.getContent() != null ? doc.getContent().length() : 0;\n int editCount = historyRepository.countByDocId(doc.getId());\n return RequirementDocStatistics.builder()\n .wordCount(wordCount)\n .editCount(editCount)\n .build();\n }\n}\n```\n\n**前端查询示例:**\n\n```graphql\nquery {\n requirementDocs(page: 0, size: 10) {\n content {\n id\n title\n ...BasicFields # 只加载基础字段\n user {\n username\n avatar\n }\n }\n }\n}\n```\n\n### 2.7 PRD 需求文档流水线\n\n#### 2.7.1 流水线架构\n\n```\n用户输入想法\n │\n ▼\n┌─────────┐ ┌─────────┐ ┌─────────────┐\n│ Outline │───▶│ Draft │───▶│ Critique │◀──┐\n│ 大纲 │ │ 初稿 │ │ 评审 │ │\n└─────────┘ └─────────┘ └─────────────┘ │\n │ │\n ▼ │\n ┌───────────┐ │\n │ Revise │────┘\n │ 修订 │ (最多3轮)\n └───────────┘\n │\n ▼\n ┌───────────┐\n │ Complete │\n │ 完成 │\n └───────────┘\n```\n\n#### 2.7.2 流水线实现\n\n```java\n@Service\npublic class PrdPipelineServiceImpl implements PrdPipelineService {\n\n private static final int MAX_REVISIONS = 3;\n private static final String APPROVAL_PHRASE = \"No issues found.\";\n\n private static final String OUTLINE_PROMPT = \"\"\"\n You are a world-class product manager. Your task is to create a structured\n outline for a Product Requirements Document (PRD)...\n \"\"\";\n\n private static final String CRITIQUE_PROMPT = \"\"\"\n You are a meticulous and critical product manager...\n If the PRD is well-structured, respond with \"No issues found.\"\n \"\"\";\n\n @Async\n @Override\n public void runPipelineAsync(String runId, String idea, Long userId) {\n String content = \"# PRD for \" + idea;\n int revision = 0;\n\n try {\n // Step 1: 生成大纲\n sendState(runId, \"Outline\", content, revision, null);\n content = aiChatService.ask(String.format(OUTLINE_PROMPT, idea), ...);\n revision++;\n\n // Step 2: 生成初稿\n sendState(runId, \"Draft\", content, revision, null);\n content = aiChatService.ask(String.format(DRAFT_PROMPT, content), ...);\n revision++;\n\n // Step 3: 评审循环\n for (int i = 0; i < MAX_REVISIONS; i++) {\n sendState(runId, \"Critique\", content, revision, null);\n String critique = aiChatService.ask(String.format(CRITIQUE_PROMPT, content), ...);\n\n if (critique.contains(APPROVAL_PHRASE)) {\n break; // 通过评审\n }\n\n // 根据评审意见修订\n content = aiChatService.ask(String.format(REVISE_PROMPT, content, critique), ...);\n revision++;\n }\n\n sendState(runId, \"Complete\", content, revision, null);\n } catch (Exception e) {\n sendState(runId, \"Error\", content, revision + 1, null);\n }\n }\n}\n```\n\n**面试要点:**\n\n1. **@Async 异步执行**:避免长时间阻塞 HTTP 请求,通过 SSE 推送进度\n2. **评审循环**:最多 3 轮修订,确保文档质量\n3. **状态推送**:通过 PrdStreamHolder 实时推送流水线状态\n\n### 2.8 限流与审计\n\n#### 2.8.1 基于 Redis 的 IP 限流\n\n```java\n@Service\npublic class RateLimitService {\n\n private final StringRedisTemplate redisTemplate;\n\n private static final String KEY_PREFIX = \"chat_limit:\";\n private static final int MAX_REQUESTS = 5; // 每日最大请求次数\n private static final Duration EXPIRATION = Duration.ofHours(24);\n\n public boolean checkAndIncrement(String ip) {\n String key = KEY_PREFIX + ip;\n\n Long count = redisTemplate.opsForValue().increment(key);\n\n // 首次请求设置过期时间\n if (count != null && count == 1) {\n redisTemplate.expire(key, EXPIRATION);\n }\n\n if (count != null && count > MAX_REQUESTS) {\n log.warn(\"Rate limit exceeded for IP: {} (Count: {})\", ip, count);\n return false;\n }\n\n return true;\n }\n}\n```\n\n**限流算法:计数器算法**\n\n- 优点:实现简单,内存占用小\n- 缺点:存在临界问题(可在临界点突发请求)\n- 改进方案:滑动窗口、令牌桶、漏桶\n\n#### 2.8.2 Token 消耗审计\n\n```java\npublic interface TokenUsageAuditService {\n void record(String provider, String modelName, Long userId, String sessionId,\n Integer inputTokens, Integer outputTokens,\n long responseTimeMs, boolean streaming);\n}\n```\n\n记录每次 AI 调用的:\n\n- Token 消耗量(输入/输出)\n- 响应时间\n- 模型提供商\n- 用户/会话信息\n\n---\n\n## 三、前端架构详解 (vue-app)\n\n### 3.1 项目结构\n\n```\nvue-app/\n├── src/\n│ ├── components/ # 可复用组件\n│ │ ├── Sidebar/ # 侧边栏组件\n│ │ ├── AppHeader.vue # 头部组件\n│ │ └── RequirementManager.vue # PRD 管理组件\n│ ├── composables/ # 组合式函数 (Hooks)\n│ │ └── useGraphQLClient.js\n│ ├── config/ # 配置文件\n│ │ └── api.js # API 端点配置\n│ ├── stores/ # Pinia 状态管理\n│ │ ├── auth.js # 认证状态\n│ │ ├── chat.js # 聊天状态\n│ │ ├── cloudDisk.js # 云盘状态\n│ │ └── theme.js # 主题状态\n│ ├── utils/ # 工具函数\n│ │ ├── request.js # Axios 封装\n│ │ ├── rsaEncryption.js # RSA 加密\n│ │ └── graphqlClient.js # GraphQL 客户端\n│ ├── views/ # 页面视图\n│ │ ├── auth/ # 认证相关页面\n│ │ ├── ChatView.vue # AI 对话页面\n│ │ ├── CloudDiskView.vue # 云盘页面\n│ │ └── WordGameView.vue # 单词记忆入口\n│ ├── router/ # 路由配置\n│ │ └── index.js\n│ ├── App.vue # 根组件\n│ └── main.js # 入口文件\n├── vite.config.js # Vite 配置\n└── package.json\n```\n\n### 3.2 Vite 构建优化\n\n```javascript\nexport default defineConfig({\n plugins: [vue()],\n resolve: {\n alias: {\n \"@\": fileURLToPath(new URL(\"./src\", import.meta.url)),\n },\n },\n server: {\n port: 3000,\n proxy: {\n \"/api\": {\n target: \"http://localhost:5000\", // 代理到后端\n changeOrigin: true,\n },\n },\n },\n build: {\n outDir: \"dist\",\n sourcemap: false,\n rollupOptions: {\n output: {\n manualChunks: {\n \"vue-vendor\": [\"vue\", \"vue-router\", \"pinia\"], // Vue 全家桶\n highlight: [\"highlight.js\"], // 代码高亮\n markdown: [\"marked\"], // Markdown 解析\n },\n },\n },\n },\n});\n```\n\n**构建优化策略:**\n\n1. **代码分割 (Code Splitting)**:将第三方库分离,利用浏览器缓存\n2. **Tree Shaking**:Vite 基于 ES Module,自动移除未使用代码\n3. **开发代理**:避免 CORS 问题,统一 API 路径\n\n### 3.3 Pinia 状态管理\n\n#### 3.3.1 认证状态管理 (auth.js)\n\n```javascript\nimport { defineStore } from \"pinia\";\nimport { computed, ref } from \"vue\";\n\nexport const useAuthStore = defineStore(\"auth\", () => {\n // 状态\n const token = ref(localStorage.getItem(\"token\") || \"\");\n const userInfo = ref(JSON.parse(localStorage.getItem(\"userInfo\") || \"null\"));\n\n // 计算属性\n const isAuthenticated = computed(() => !!token.value);\n const isAdmin = computed(() => userInfo.value?.is_admin === true);\n\n // 登录方法\n async function login(email, password) {\n const response = await request.post(API_ENDPOINTS.auth.login, {\n email,\n password,\n });\n\n const accessToken = response?.data?.access_token;\n if (accessToken) {\n token.value = accessToken;\n userInfo.value = {\n id: response.data.user_id,\n email: response.data.email,\n username: response.data.username,\n is_admin: response.data.is_admin,\n };\n\n // 持久化存储\n localStorage.setItem(\"token\", token.value);\n localStorage.setItem(\"userInfo\", JSON.stringify(userInfo.value));\n\n return { success: true };\n }\n return { success: false };\n }\n\n // 退出登录\n function logout() {\n token.value = \"\";\n userInfo.value = null;\n localStorage.removeItem(\"token\");\n localStorage.removeItem(\"userInfo\");\n }\n\n return {\n token,\n userInfo,\n isAuthenticated,\n isAdmin,\n login,\n logout,\n };\n});\n```\n\n**Pinia vs Vuex 对比:**\n| 特性 | Vuex | Pinia |\n|------|------|-------|\n| 状态定义 | state 对象 | ref/reactive |\n| 修改方式 | mutations | 直接修改 |\n| TypeScript | 需要额外配置 | 原生支持 |\n| 模块化 | modules | 独立 Store |\n| DevTools | 支持 | 支持 |\n\n#### 3.3.2 聊天状态管理 (chat.js)\n\n```javascript\nexport const useChatStore = defineStore(\"chat\", () => {\n const sessions = ref([]);\n const currentSessionId = ref(null);\n const messages = ref([]);\n const isLoading = ref(false);\n const abortController = ref(null);\n const selectedModel = ref(localStorage.getItem(\"selectedModel\") || \"deepseek-chat\");\n\n // 流式发送消息\n async function sendMessage(content, onChunk) {\n isLoading.value = true;\n abortController.value = new AbortController();\n\n // 添加用户消息\n messages.value.push({\n role: \"user\",\n content,\n timestamp: new Date().toISOString(),\n });\n\n // 添加 AI 消息占位符\n const aiMessage = {\n role: \"assistant\",\n content: \"\",\n reasoning_content: \"\",\n isStreaming: true,\n timestamp: new Date().toISOString(),\n };\n messages.value.push(aiMessage);\n\n try {\n const response = await fetch(\"/api/ask-stream\", {\n method: \"POST\",\n signal: abortController.value.signal,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authStore.token}`,\n },\n body: JSON.stringify({\n prompt: content,\n session_id: currentSessionId.value,\n model: selectedModel.value,\n }),\n });\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"data:\")) {\n const data = line.slice(5).trim();\n if (data === \"[DONE]\") continue;\n\n const parsed = JSON.parse(data);\n\n // 处理推理内容\n if (parsed.reasoning_content) {\n aiMessage.reasoning_content += parsed.reasoning_content;\n }\n\n // 处理回复内容\n if (parsed.content) {\n aiMessage.content += parsed.content;\n }\n }\n }\n }\n\n aiMessage.isStreaming = false;\n return { success: true };\n } catch (error) {\n if (error.name === \"AbortError\") {\n console.log(\"Generation aborted by user\");\n return { success: true, aborted: true };\n }\n throw error;\n } finally {\n isLoading.value = false;\n }\n }\n\n // 停止生成\n function stopGeneration() {\n if (abortController.value) {\n abortController.value.abort();\n }\n }\n\n return {\n sessions,\n messages,\n isLoading,\n selectedModel,\n sendMessage,\n stopGeneration,\n };\n});\n```\n\n**SSE 客户端实现要点:**\n\n1. **ReadableStream API**:原生流式读取响应体\n2. **AbortController**:支持取消请求\n3. **增量更新**:逐字符追加内容,实现打字机效果\n\n### 3.4 前端安全措施\n\n1. **XSS 防护**:使用 DOMPurify 清理用户输入\n2. **密码加密**:RSA 非对称加密传输\n3. **Token 存储**:localStorage + XSS 风险权衡\n4. **CORS 配置**:后端白名单控制\n\n---\n\n## 四、单词记忆模块 (word-game)\n\n### 4.1 技术架构\n\n```\nword-game/\n├── server/ # Node.js 后端\n│ ├── index.js # Express 服务入口\n│ └── progress.db # SQLite 数据库\n├── src/ # Vue 3 前端\n│ ├── components/\n│ │ ├── game/ # 游戏组件\n│ │ │ ├── AnswerView.vue\n│ │ │ ├── TypingInput.vue\n│ │ │ └── CompletionModal.vue\n│ │ └── pages/ # 页面组件\n│ ├── composables/ # 组合式函数\n│ │ ├── useEnglishSound.ts # 发音功能\n│ │ └── useQuestion.ts # 题目逻辑\n│ ├── stores/ # Pinia 状态\n│ │ ├── courseStore.ts\n│ │ └── progressStore.ts\n│ └── services/\n│ └── wordGameApi.ts # API 封装\n└── vite.config.ts\n```\n\n### 4.2 后端实现 (Express 5 + SQLite)\n\n#### 4.2.1 数据库设计\n\n```javascript\nconst db = new Database(join(__dirname, \"progress.db\"));\ndb.pragma(\"journal_mode = WAL\"); // Write-Ahead Logging 提升并发性能\n\ndb.exec(`\n -- 用户学习进度表\n CREATE TABLE IF NOT EXISTS course_progress (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n user_key TEXT NOT NULL, -- 用户标识(userId 或 guest_IP)\n user_type TEXT NOT NULL DEFAULT 'guest',\n package_id TEXT NOT NULL, -- 课程包 ID\n course_index INTEGER NOT NULL, -- 课程索引\n current_q INTEGER NOT NULL DEFAULT 0, -- 当前题目\n completed INTEGER NOT NULL DEFAULT 0, -- 是否完成\n study_secs INTEGER NOT NULL DEFAULT 0, -- 学习时长\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n UNIQUE(user_key, package_id, course_index)\n );\n\n -- 用户自定义课程包\n CREATE TABLE IF NOT EXISTS user_packages (\n id TEXT PRIMARY KEY,\n user_key TEXT NOT NULL,\n name TEXT NOT NULL,\n description TEXT NOT NULL DEFAULT '',\n icon TEXT NOT NULL DEFAULT '📦',\n is_public INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n -- 课程包题目\n CREATE TABLE IF NOT EXISTS user_package_statements (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n package_id TEXT NOT NULL,\n course_index INTEGER NOT NULL DEFAULT 0,\n english TEXT NOT NULL,\n chinese TEXT NOT NULL,\n soundmark TEXT NOT NULL DEFAULT ''\n );\n`);\n```\n\n**SQLite 优势:**\n\n1. **零配置**:无需独立数据库服务\n2. **单文件存储**:便于备份和迁移\n3. **WAL 模式**:提升并发读写性能\n4. **适合场景**:嵌入式应用、小型项目、开发测试\n\n#### 4.2.2 JWT 认证中间件\n\n```javascript\n/**\n * 与主站共享 JWT 密钥,实现单点登录\n */\nfunction requireAispringAuth(req, res, next) {\n try {\n const auth = req.headers[\"authorization\"];\n if (!auth || !auth.startsWith(\"Bearer \")) {\n return res.status(401).json({ success: false, message: \"未登录\" });\n }\n\n const token = auth.slice(7);\n const key = getJwtSigningKey(); // 与主站一致的密钥\n\n jwt.verify(token, key, { algorithms: [\"HS256\"] });\n next();\n } catch (err) {\n const msg = err.name === \"TokenExpiredError\" ? \"登录已过期\" : \"无效的登录凭证\";\n res.status(401).json({ success: false, message: msg });\n }\n}\n\n// 应用中间件\napp.use(\"/api\", requireAispringAuth);\n```\n\n#### 4.2.3 核心路由\n\n```javascript\n// 获取课程包列表(支持搜索、按点击量排序)\napp.get(\"/api/packages\", (req, res) => {\n const { key } = resolveUserKey(req);\n const search = req.query.search;\n\n let list = [...PACKAGES]; // 内置课程包\n const userRows = getUserPackagesList(key, search);\n list.push(...userRows.map(userPackageToMeta));\n\n // 按点击量排序\n list.sort((a, b) => (b.clickCount || 0) - (a.clickCount || 0));\n\n res.json({ success: true, data: list });\n});\n\n// 获取课程题目\napp.get(\"/api/courses/:courseIndex/questions\", (req, res) => {\n const packageId = req.query.packageId;\n const idx = parseInt(req.params.courseIndex, 10);\n\n if (packageId && packageId.startsWith(\"up-\")) {\n // 用户自定义课程包\n const rows = db.prepare(`\n SELECT english, chinese, soundmark\n FROM user_package_statements\n WHERE package_id = ? AND course_index = ?\n ORDER BY sort_order, id\n `).all(packageId, idx - 1);\n return res.json({ success: true, data: rows });\n }\n\n // 内置课程包\n const filePath = join(COURSES_DIR, `${String(idx).padStart(2, \"0\")}.json`);\n const statements = JSON.parse(readFileSync(filePath, \"utf-8\"));\n res.json({ success: true, data: statements });\n});\n\n// 创建自定义课程包\napp.post(\"/api/packages\", (req, res) => {\n const { key } = resolveUserKey(req);\n const { name, description, sections, isPublic } = req.body;\n\n const packageId = \"up-\" + randomUUID().replace(/-/g, \"\").slice(0, 16);\n\n db.transaction(() => {\n // 插入课程包元数据\n db.prepare(`INSERT INTO user_packages ...`).run(packageId, key, name, ...);\n\n // 插入各节题目\n for (const section of sections) {\n for (const stmt of section.statements) {\n db.prepare(`INSERT INTO user_package_statements ...`).run(...);\n }\n }\n })();\n\n res.status(201).json({ success: true, data: { id: packageId } });\n});\n```\n\n### 4.3 前端实现\n\n#### 4.3.1 打字输入组件\n\n```vue\n\n\n\n```\n\n#### 4.3.2 发音功能实现\n\n```typescript\nexport function useEnglishSound() {\n const audioContext = new (window.AudioContext || window.webkitAudioContext)()\n\n async function play(text: string) {\n // 使用 Web Speech API\n const utterance = new SpeechSynthesisUtterance(text)\n utterance.lang = 'en-US'\n utterance.rate = 0.9\n speechSynthesis.speak(utterance)\n }\n\n return { play }\n}\n```\n\n### 4.4 iframe 跨域通信\n\n主站通过 iframe 嵌入单词记忆模块,使用 postMessage 实现通信:\n\n```vue\n\n\n\n\n```\n\n---\n\n## 五、部署架构\n\n### 5.1 生产环境部署\n\n```\n ┌─────────────────────────────────────┐\n │ Nginx (反向代理) │\n │ Port: 80 / 443 │\n └─────────────────────────────────────┘\n │\n ┌───────────────────────────┼───────────────────────────┐\n │ │ │\n ▼ ▼ ▼\n┌───────────────┐ ┌───────────────┐ ┌───────────────┐\n│ aistudy.icu │ │ earthworm. │ │ 静态资源 │\n│ (主站) │ │ aistudy.icu │ │ (CDN) │\n│ → :5000 │ │ → :5201 │ │ │\n└───────────────┘ └───────────────┘ └───────────────┘\n │ │\n ▼ ▼\n┌───────────────┐ ┌───────────────┐\n│ Spring Boot │ │ Node.js │\n│ JAR / Docker │ │ Express │\n└───────────────┘ └───────────────┘\n │ │\n └───────────┬───────────────┘\n ▼\n ┌───────────────────────┐\n │ MySQL 8.x │\n │ Redis 7.x │\n └───────────────────────┘\n```\n\n### 5.2 Nginx 配置示例\n\n```nginx\n# 主站\nserver {\n listen 80;\n server_name aistudy.icu;\n\n location / {\n proxy_pass http://127.0.0.1:5000;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n\n # SSE 支持\n proxy_http_version 1.1;\n proxy_set_header Connection '';\n proxy_buffering off;\n proxy_cache off;\n proxy_read_timeout 300s;\n }\n}\n\n# 单词记忆模块\nserver {\n listen 80;\n server_name earthworm.aistudy.icu;\n\n location / {\n proxy_pass http://127.0.0.1:5201;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n }\n}\n```\n\n---\n\n## 六、性能优化总结\n\n### 6.1 后端优化\n\n| 优化点 | 实现方式 | 效果 |\n| ---------- | ------------------ | ---------------- |\n| 数据库索引 | 复合索引、覆盖索引 | 查询性能提升 10x |\n| 连接池 | HikariCP 默认配置 | 减少连接创建开销 |\n| 异步处理 | @Async + 线程池 | 非阻塞响应 |\n| 缓存策略 | Redis + 本地缓存 | 减少数据库压力 |\n| 流式响应 | SSE | 首字节时间优化 |\n\n### 6.2 前端优化\n\n| 优化点 | 实现方式 | 效果 |\n| -------- | -------------------- | ---------------- |\n| 代码分割 | manualChunks | 首屏加载减少 60% |\n| 懒加载 | 路由懒加载 | 按需加载页面 |\n| 虚拟滚动 | vue-virtual-scroller | 大列表性能优化 |\n| 防抖节流 | lodash | 减少无效请求 |\n| 缓存策略 | localStorage | 减少网络请求 |\n\n---\n\n## 七、面试高频问题\n\n### Q1: 为什么选择 Spring Boot 3.x?\n\n**回答要点:**\n\n1. 要求 Java 17+,支持 Virtual Threads(虚拟线程),大幅提升并发性能\n2. 原生支持 GraalVM 编译为原生可执行文件,启动时间从秒级降到毫秒级\n3. ProblemDetail API 标准化错误响应\n4. 可观测性增强(Micrometer Tracing)\n\n### Q2: JWT Token 如何实现续期?\n\n**回答要点:**\n\n1. **短期 Token + Refresh Token**:Access Token 有效期短(如 30 分钟),Refresh Token 有效期长(如 7 天)\n2. **滑动过期**:每次请求检查 Token 剩余有效期,若低于阈值则生成新 Token 返回\n3. **本项目方案**:Token 有效期 24 小时,过期后需重新登录\n\n### Q3: 如何防止 XSS 攻击?\n\n**回答要点:**\n\n1. **输入过滤**:使用 DOMPurify 清理用户输入\n2. **输出编码**:Vue 自动转义插值表达式\n3. **CSP 策略**:Content-Security-Policy 头限制脚本来源\n4. **HttpOnly Cookie**:敏感 Cookie 不允许 JS 访问(本项目使用 localStorage,需权衡)\n\n### Q4: SSE 和 WebSocket 如何选择?\n\n| 特性 | SSE | WebSocket |\n| -------- | --------------------- | -------------- |\n| 通信方向 | 单向(服务器→客户端) | 双向 |\n| 协议 | HTTP | WS/WSS |\n| 重连 | 浏览器自动重连 | 需手动实现 |\n| 适用场景 | 推送通知、AI 流式输出 | 实时聊天、游戏 |\n\n**本项目选择 SSE 的原因**:AI 对话场景只需服务器向客户端推送数据,SSE 更简单、更轻量。\n\n### Q5: 如何保证数据库与缓存一致性?\n\n**回答要点:**\n\n1. **Cache-Aside 模式**:先更新数据库,再删除缓存\n2. **延迟双删**:删除缓存 → 更新数据库 → 延迟再删除缓存\n3. **消息队列**:通过消息队列保证最终一致性\n4. **本项目方案**:写操作直接更新数据库,读操作先查缓存再查数据库\n\n---\n\n## 八、技术亮点总结\n\n1. **多模型 AI 集成**:通过 Spring AI 统一抽象层,支持 DeepSeek、豆包等多个模型\n2. **流式响应优化**:SSE 实现打字机效果,提升用户体验\n3. **GraphQL 按需加载**:解决 REST API 过度获取/获取不足问题\n4. **PRD 流水线**:多阶段 AI 协作,自动生成需求文档\n5. **微前端架构**:iframe + postMessage 实现模块解耦\n6. **安全加固**:RSA 加密传输 + JWT 认证 + 限流防护\n\n---\n\n_文档版本: 2.0_ \n_最后更新: 2026-02-28_\n"}}, "aispring/src/main/resources/application.yml": {"e8e062a225b43bf79ca9e278530fca7c457c0fcd": {"t": 1785746941.9022975, "n": 5797, "h": "332371a2f595ee8a", "c": "spring:\n mvc:\n async:\n request-timeout: 300000 # 5 minutes\n application:\n name: ai-smart-tutor\n \n # Jackson JSON 序列化配置(将下划线转为驼峰)\n jackson:\n property-naming-strategy: LOWER_CAMEL_CASE # 使用驼峰命名(默认)\n \n # 触发DevTools重启\n # 禁用 GraphQL\n graphql:\n graphiql:\n enabled: false\n autoconfigure:\n exclude:\n - org.springframework.boot.autoconfigure.graphql.GraphQlAutoConfiguration\n - org.springframework.boot.autoconfigure.graphql.servlet.GraphQlWebMvcAutoConfiguration\n \n # 数据库配置(极致优化:最小化连接池以大幅降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=1024\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 1\n maximum-pool-size: 5\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(极致优化:最小化连接池)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 5\n max-idle: 2\n min-idle: 1\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(极致优化:大幅减少线程数和连接数以降低内存)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 50\n min-spare: 5\n max-connections: 200\n accept-count: 50\n connection-timeout: 300000 # 增加到 5 分钟,防止大文件传输中断\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:ENC(WOJOOCuurFh7APQ9My08lHfUm0dhMAO6fHVtAjblLdggFWyOZicuHGj0HUH29opv)}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://localhost:4173,http://127.0.0.1:3000,http://127.0.0.1:5173,http://127.0.0.1:4173,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n # 用户数据存储:开发默认当前目录;生产环境由 application-prod 指定项目外专用目录\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n"}, "66d582c2643956640599f78c65bed8d6caee84d5": {"t": 1785765998.7814047, "n": 5797, "h": "332371a2f595ee8a", "c": "spring:\n mvc:\n async:\n request-timeout: 300000 # 5 minutes\n application:\n name: ai-smart-tutor\n \n # Jackson JSON 序列化配置(将下划线转为驼峰)\n jackson:\n property-naming-strategy: LOWER_CAMEL_CASE # 使用驼峰命名(默认)\n \n # 触发DevTools重启\n # 禁用 GraphQL\n graphql:\n graphiql:\n enabled: false\n autoconfigure:\n exclude:\n - org.springframework.boot.autoconfigure.graphql.GraphQlAutoConfiguration\n - org.springframework.boot.autoconfigure.graphql.servlet.GraphQlWebMvcAutoConfiguration\n \n # 数据库配置(极致优化:最小化连接池以大幅降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=1024\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 1\n maximum-pool-size: 5\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(极致优化:最小化连接池)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 5\n max-idle: 2\n min-idle: 1\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(极致优化:大幅减少线程数和连接数以降低内存)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 50\n min-spare: 5\n max-connections: 200\n accept-count: 50\n connection-timeout: 300000 # 增加到 5 分钟,防止大文件传输中断\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:ENC(WOJOOCuurFh7APQ9My08lHfUm0dhMAO6fHVtAjblLdggFWyOZicuHGj0HUH29opv)}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://localhost:4173,http://127.0.0.1:3000,http://127.0.0.1:5173,http://127.0.0.1:4173,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n # 用户数据存储:开发默认当前目录;生产环境由 application-prod 指定项目外专用目录\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n"}, "80118682ea117636e7afe5c402a837535d97006b": {"t": 1785766000.3144174, "n": 5744, "h": "12c73fe960d0ec82", "c": "spring:\n mvc:\n async:\n request-timeout: 300000 # 5 minutes\n application:\n name: ai-smart-tutor\n \n # Jackson JSON 序列化配置(将下划线转为驼峰)\n jackson:\n property-naming-strategy: LOWER_CAMEL_CASE # 使用驼峰命名(默认)\n \n # 触发DevTools重启\n # 禁用 GraphQL\n graphql:\n graphiql:\n enabled: false\n autoconfigure:\n exclude:\n - org.springframework.boot.autoconfigure.graphql.GraphQlAutoConfiguration\n - org.springframework.boot.autoconfigure.graphql.servlet.GraphQlWebMvcAutoConfiguration\n \n # 数据库配置(极致优化:最小化连接池以大幅降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=1024\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 1\n maximum-pool-size: 5\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(极致优化:最小化连接池)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 5\n max-idle: 2\n min-idle: 1\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(极致优化:大幅减少线程数和连接数以降低内存)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 50\n min-spare: 5\n max-connections: 200\n accept-count: 50\n connection-timeout: 300000 # 增加到 5 分钟,防止大文件传输中断\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:ENC(WOJOOCuurFh7APQ9My08lHfUm0dhMAO6fHVtAjblLdggFWyOZicuHGj0HUH29opv)}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://localhost:4173,http://127.0.0.1:3000,http://127.0.0.1:5173,http://127.0.0.1:4173,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n"}, "26091356bcf1c53066317af7cb88a869e00c2645": {"t": 1785766002.0197964, "n": 5352, "h": "118d29716300466d", "c": "spring:\n mvc:\n async:\n request-timeout: 300000 # 5 minutes\n application:\n name: ai-smart-tutor\n \n # 数据库配置(极致优化:最小化连接池以大幅降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=1024\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 1\n maximum-pool-size: 5\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(极致优化:最小化连接池)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 5\n max-idle: 2\n min-idle: 1\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(极致优化:大幅减少线程数和连接数以降低内存)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 50\n min-spare: 5\n max-connections: 200\n accept-count: 50\n connection-timeout: 300000 # 增加到 5 分钟,防止大文件传输中断\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:ENC(WOJOOCuurFh7APQ9My08lHfUm0dhMAO6fHVtAjblLdggFWyOZicuHGj0HUH29opv)}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://localhost:4173,http://127.0.0.1:3000,http://127.0.0.1:5173,http://127.0.0.1:4173,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n"}, "f85aea6d2d93d53c63d9951df77a83dbfbaa1582": {"t": 1785766003.5433655, "n": 5292, "h": "4af4a120968c96f0", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置(极致优化:最小化连接池以大幅降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=1024\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 1\n maximum-pool-size: 5\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(极致优化:最小化连接池)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 5\n max-idle: 2\n min-idle: 1\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(极致优化:大幅减少线程数和连接数以降低内存)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 50\n min-spare: 5\n max-connections: 200\n accept-count: 50\n connection-timeout: 300000 # 增加到 5 分钟,防止大文件传输中断\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:ENC(WOJOOCuurFh7APQ9My08lHfUm0dhMAO6fHVtAjblLdggFWyOZicuHGj0HUH29opv)}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://localhost:4173,http://127.0.0.1:3000,http://127.0.0.1:5173,http://127.0.0.1:4173,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n"}, "6dfb2d0a4bf958ed8f57bb15dd548d1c76e0a669": {"t": 1785766005.024385, "n": 5270, "h": "0a6987417eecca84", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置(极致优化:最小化连接池以大幅降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=1024\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 1\n maximum-pool-size: 5\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(极致优化:最小化连接池)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 5\n max-idle: 2\n min-idle: 1\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(极致优化:大幅减少线程数和连接数以降低内存)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 50\n min-spare: 5\n max-connections: 200\n accept-count: 50\n connection-timeout: 60000\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:ENC(WOJOOCuurFh7APQ9My08lHfUm0dhMAO6fHVtAjblLdggFWyOZicuHGj0HUH29opv)}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://localhost:4173,http://127.0.0.1:3000,http://127.0.0.1:5173,http://127.0.0.1:4173,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n"}, "2522cb0562c71bbe3db552e44d90c92090da8205": {"t": 1785766006.7130783, "n": 5204, "h": "400e14ab5e5ada2b", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置(极致优化:最小化连接池以大幅降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=1024\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 1\n maximum-pool-size: 5\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(极致优化:最小化连接池)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 5\n max-idle: 2\n min-idle: 1\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(极致优化:大幅减少线程数和连接数以降低内存)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 50\n min-spare: 5\n max-connections: 200\n accept-count: 50\n connection-timeout: 60000\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:ENC(wbBUUElYyKgb7BxF7CgZ/wpR3RHQdJ3TgxHIhSQ0GQck1QPp1/wwd0JdHmQ7W9Xk)}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:ENC(WOJOOCuurFh7APQ9My08lHfUm0dhMAO6fHVtAjblLdggFWyOZicuHGj0HUH29opv)}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n"}, "701cf14f33422901d62ef01b9b2fb8171062ae93": {"t": 1785766008.2328632, "n": 5138, "h": "273fe2df2dcf18bb", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置(极致优化:最小化连接池以大幅降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=1024\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 1\n maximum-pool-size: 5\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(极致优化:最小化连接池)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 5\n max-idle: 2\n min-idle: 1\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(PXkZZlkx8FKyKOigb+jXg54bgTu/38HyEAjzh74ohFt0yN8NfIWqAd0flh3y4p2q)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(极致优化:大幅减少线程数和连接数以降低内存)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 50\n min-spare: 5\n max-connections: 200\n accept-count: 50\n connection-timeout: 60000\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n\n"}, "2633330805c4ffd3413042f60bea72e2643fbb5d": {"t": 1785766009.6220639, "n": 5135, "h": "bd192b9d36f38552", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置(优化:减少连接池大小以降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=250&prepStmtCacheSqlLimit=2048\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 2\n maximum-pool-size: 10\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(优化:减少连接池大小)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 10\n max-idle: 5\n min-idle: 2\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 1000MB\n max-request-size: 1000MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(PXkZZlkx8FKyKOigb+jXg54bgTu/38HyEAjzh74ohFt0yN8NfIWqAd0flh3y4p2q)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(优化:添加线程配置和连接超时配置)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 100\n min-spare: 10\n max-connections: 1000\n accept-count: 100\n connection-timeout: 60000\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n\n"}, "1e1399045962266b24c9da6a9a114739512f581e": {"t": 1785766011.1576989, "n": 5133, "h": "c11db736263c0d01", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置(优化:减少连接池大小以降低内存占用)\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&cachePrepStmts=true&prepStmtCacheSize=250&prepStmtCacheSqlLimit=2048\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 2\n maximum-pool-size: 10\n idle-timeout: 600000\n connection-timeout: 30000\n max-lifetime: 1800000\n leak-detection-threshold: 60000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置(优化:减少内存占用,提高性能)\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: false\n properties:\n hibernate:\n \"[format_sql]\": false\n \"[jdbc.batch_size]\": 20\n \"[order_inserts]\": true\n \"[order_updates]\": true\n \"[jdbc.batch_versioned_data]\": true\n \"[generate_statistics]\": false\n \"[cache.use_second_level_cache]\": false\n \"[cache.use_query_cache]\": false\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储(优化:减少连接池大小)\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 3000ms\n lettuce:\n pool:\n max-active: 10\n max-idle: 5\n min-idle: 2\n max-wait: 3000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置(优化:不限制上传时间,基于大小限制,提高临时文件阈值以减少磁盘IO)\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 10MB\n # 使用流式处理,避免将整个文件加载到内存\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(PXkZZlkx8FKyKOigb+jXg54bgTu/38HyEAjzh74ohFt0yN8NfIWqAd0flh3y4p2q)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置(优化:添加线程配置和连接超时配置)\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n tomcat:\n threads:\n max: 100\n min-spare: 10\n max-connections: 1000\n accept-count: 100\n connection-timeout: 60000\n max-http-form-post-size: -1\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置(优化:减少SQL日志输出以降低内存和IO开销)\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": INFO\n \"[org.springframework.web]\": WARN\n \"[org.hibernate.SQL]\": WARN\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": WARN\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 15\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n\n"}, "ba818b965cd47d653d83c89b3f0555ff9eb512ae": {"t": 1785766012.6000047, "n": 4411, "h": "155f83d6be14ca88", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(PXkZZlkx8FKyKOigb+jXg54bgTu/38HyEAjzh74ohFt0yN8NfIWqAd0flh3y4p2q)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n file:\n # 启动时自动清理孤立的文件记录(数据库中存在但物理文件不存在)\n # 设置为 false 可禁用自动清理\n auto-cleanup-on-startup: true\n\n"}, "e75385858e413b3131fee2bc6a074fd16a52c21b": {"t": 1785766014.2422338, "n": 4308, "h": "a0864d2782264429", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(PXkZZlkx8FKyKOigb+jXg54bgTu/38HyEAjzh74ohFt0yN8NfIWqAd0flh3y4p2q)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "cc6661a63a7cddd6c80788107fae4d22d77f797e": {"t": 1785766015.513871, "n": 4308, "h": "2c75298675c14a71", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n validate-on-migrate: false\n locations: classpath:db/migration\n\n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(PXkZZlkx8FKyKOigb+jXg54bgTu/38HyEAjzh74ohFt0yN8NfIWqAd0flh3y4p2q)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "a3e058a386de179be93739f2267593937f5d71bc": {"t": 1785766017.0157943, "n": 4277, "h": "586aeb5334482bc1", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:ENC(ChwOBS62kHNKHEfErml6nw==)}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n locations: classpath:db/migration\n\n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:ENC(LZy5qJumY+qHyFxAmZ3NLwqIl6mXaN/CBQ8KrjhAEIg=)}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:ENC(PXkZZlkx8FKyKOigb+jXg54bgTu/38HyEAjzh74ohFt0yN8NfIWqAd0flh3y4p2q)}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n\n# Jasypt 加密配置\njasypt:\n encryptor:\n password: ${JASYPT_PASSWORD:aistudy_secret}\n algorithm: PBEWithMD5AndDES\n iv-generator-classname: org.jasypt.iv.NoIvGenerator\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "7afa89fdd357a3b340a7ffb007e6916649b0cd6d": {"t": 1785766018.6395051, "n": 4015, "h": "409538ddae6da2e1", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:123456}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n locations: classpath:db/migration\n\n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-7f17e997c31e4d82bf0286116ad34226}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "cfd5891c7d6966e98f3bd830d9952e026c070ac7": {"t": 1785766020.546475, "n": 4015, "h": "50ef2527d25fed32", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:123456}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n locations: classpath:db/migration\n\n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "e98facd48748eab5a3f91f2334cb984b331fbc39": {"t": 1785766022.5201743, "n": 4068, "h": "b4da158d0fe1b3a8", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:123456}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n locations: classpath:db/migration\n\n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://aistudy.icu,https://aistudy.icu,http://www.aistudy.icu,https://www.aistudy.icu\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "17d22879142605e5a65babcb2b84d3cc7051244f": {"t": 1785766024.0584168, "n": 3982, "h": "39dc4c4e247022b2", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:123456}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # Flyway 配置\n flyway:\n enabled: true\n baseline-on-migrate: true\n baseline-version: 1\n locations: classpath:db/migration\n\n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "677822bb6aa5a354aad1119c4bdb41d3d1c381f7": {"t": 1785766025.5711286, "n": 3847, "h": "254e4e1f88d5d9f1", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:ipv6_education}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: ${DB_USERNAME:root}\n password: ${DB_PASSWORD:123456}\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置 (生产环境默认禁用)\n devtools:\n restart:\n enabled: false\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: false\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "7fda2dacd8a9036e8414337ef3815506a3a9f176": {"t": 1785766027.1234593, "n": 3771, "h": "a6de2a10792ab47a", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n \"[format_sql]\": true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n \"[com.aispring]\": DEBUG\n \"[org.springframework.web]\": INFO\n \"[org.hibernate.SQL]\": DEBUG\n \"[org.hibernate.type.descriptor.sql.BasicBinder]\": TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "d7395b740326767dcca1e2aadc3abb8d681bfa4e": {"t": 1785766028.6566975, "n": 3751, "h": "a774211e7895e3c7", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n auth:\n verification-code-expire-minutes: 5\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "9db8986c1d9bc1a021fb2ea65e6ca53fa6b9323b": {"t": 1785766030.1207983, "n": 4180, "h": "2ec5ba29e2c7a908", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n data:\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n # Session状态TTL配置\n session-state:\n ttl: 86400 # 24小时(秒)\n inactive-ttl: 3600 # 非活跃会话1小时后过期(秒)\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "d3a6f2822ceb58e8d10d038cc6b37e5241f20b48": {"t": 1785766031.6099982, "n": 4146, "h": "d42cde51deffcb09", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # Redis配置 - 用于Session状态存储\n redis:\n host: ${REDIS_HOST:localhost}\n port: ${REDIS_PORT:6379}\n database: ${REDIS_DATABASE:1}\n password: ${REDIS_PASSWORD:}\n timeout: 2000ms\n lettuce:\n pool:\n max-active: 20\n max-idle: 10\n min-idle: 5\n max-wait: 2000ms\n shutdown-timeout: 200ms\n # Session状态TTL配置\n session-state:\n ttl: 86400 # 24小时(秒)\n inactive-ttl: 3600 # 非活跃会话1小时后过期(秒)\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "46bb93a37aabf3b1fcc27babcd0724fa848c360b": {"t": 1785766033.5395615, "n": 3701, "h": "ed55535c8c41d0cb", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:8192}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:8192}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "e7f575d42d7106cd234e9e7c09fb432387ae1e39": {"t": 1785766034.9226599, "n": 3701, "h": "233723590c89f7c6", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:4096}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com}\n max-tokens: ${MAX_TOKEN:4096}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "0c8d0249f91880e690bb4eb13b689ae3931d4dbe": {"t": 1785766036.8737895, "n": 3693, "h": "800ff9ef0a988299", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:4096}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://api.doubao.com/v1}\n max-tokens: ${MAX_TOKEN:4096}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "a578cb3d3bb2a7267217b05cb673bc56ebcf098a": {"t": 1785766038.5939898, "n": 3748, "h": "cfdcee3c2da3c32a", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:${AI_DEEPSEEK_API_KEY:sk-placeholder}}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:4096}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:${AI_DEEPSEEK_API_KEY:}}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_API_KEY:${AI_DOUBAO_API_KEY:${DOUBAO_KEY:}}}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com/api/v3}\n model: ${DOUBAO_MODEL:${AI_DOUBAO_MODEL:}}\n max-tokens: ${MAX_TOKEN:4096}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "c813c4e1d0dd9d68ecb69dbb1745db35e0ece6e2": {"t": 1785766040.5170627, "n": 3634, "h": "f03f628938e41522", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:4096}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_API_KEY:}\n api-url: ${DOUBAO_BASEURL:https://ark.cn-beijing.volces.com/api/v3}\n model: ${DOUBAO_MODEL:}\n max-tokens: ${MAX_TOKEN:4096}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "b38d2c2f707eec9117ef3603f89753c076e596d2": {"t": 1785766042.2447956, "n": 3735, "h": "e55543e473689d87", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:4096}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://api.doubao.com/v1}\n model: ${DOUBAO_MODEL:doubao-pro-32k}\n max-tokens: ${MAX_TOKEN:4096}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "4d2455559c6555a620890eb2c3def041e93d13a8": {"t": 1785766043.8328443, "n": 3693, "h": "800ff9ef0a988299", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:4096}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://api.doubao.com/v1}\n max-tokens: ${MAX_TOKEN:4096}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}, "a899cd47d408faa96fe21e9dfb5d8519ebffae1c": {"t": 1785766045.2330306, "n": 3690, "h": "1b69cd3c5baa72b0", "c": "spring:\n application:\n name: ai-smart-tutor\n \n # 数据库配置\n datasource:\n url: jdbc:mysql://localhost:3306/ipv6_education?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\n username: root\n password: 123456\n driver-class-name: com.mysql.cj.jdbc.Driver\n hikari:\n minimum-idle: 5\n maximum-pool-size: 20\n idle-timeout: 300000\n connection-timeout: 20000\n \n # JPA配置\n jpa:\n hibernate:\n ddl-auto: update\n show-sql: true\n properties:\n hibernate:\n dialect: org.hibernate.dialect.MySQL8Dialect\n format_sql: true\n open-in-view: false\n \n # 文件上传配置\n servlet:\n multipart:\n enabled: true\n max-file-size: 500MB\n max-request-size: 500MB\n file-size-threshold: 2KB\n \n # 邮件配置\n mail:\n host: smtp.qq.com\n port: 587\n username: ${SENDER_EMAIL:3301767269@qq.com}\n password: ${SENDER_PASSWORD:dinasyxqstbodbej}\n properties:\n mail:\n smtp:\n auth: true\n starttls:\n enable: true\n required: true\n ssl:\n trust: smtp.qq.com\n \n # 热部署配置\n devtools:\n restart:\n enabled: true\n poll-interval: 2000ms\n quiet-period: 1000ms\n log-condition-evaluation-delta: false\n exclude: META-INF/maven/**,META-INF/resources/**,static/**,public/**,templates/**,**/*Test.class,**/*Tests.class\n additional-exclude: logs/**\n livereload:\n enabled: true\n add-properties: true\n \n # Spring AI配置 - DeepSeek (兼容OpenAI API)\n ai:\n openai:\n api-key: ${DEEPSEEK_API_KEY:sk-45021a61b84a4693a1db4deb72cec673}\n base-url: ${DEEPSEEK_API_URL:${DEEPSEEK_URL:https://api.deepseek.com}}\n chat:\n options:\n model: deepseek-chat\n temperature: 0.7\n max-tokens: ${MAX_TOKEN:4096}\n\n# 服务器配置\nserver:\n port: 5000\n servlet:\n context-path: /\n compression:\n enabled: true\n mime-types: application/json,application/xml,text/html,text/xml,text/plain\n\n# JWT配置\njwt:\n secret: ${JWT_SECRET_KEY:default_development_key_change_in_production}\n expiration: 7200000 # 2小时,单位毫秒\n\n# AI模型配置\nai:\n deepseek:\n api-key: ${DEEPSEEK_API_KEY:45021a61b84a4693a1db4deb72cec673}\n api-url: ${DEEPSEEK_URL:https://api.deepseek.com}\n doubao:\n api-key: ${DOUBAO_KEY:6261fd4e-7ac5-46de-95a6-f68f00243230}\n api-url: ${DOUBAO_BASEURL:https://api.doubao.com/v1}\n max-tokens: ${MAX_TOKEN:4096}\n\n# 文件存储配置\nfile:\n upload-dir: ${FILE_UPLOAD_DIR:uploads}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n max-file-size: ${MAX_FILE_SIZE:524288000} # 500MB\n allowed-extensions: jpg,jpeg,png,gif,bmp,svg,webp,txt,md,csv,json,xml,html,css,js,doc,docx,pdf,rtf,xls,xlsx,ppt,pptx,mp4,avi,mov,wmv,flv,mkv,zip,rar,7z,tar,gz\n\n# 验证码配置\nverification:\n code-expire-minutes: 5\n\n# 日志配置\nlogging:\n level:\n root: INFO\n com.aispring: DEBUG\n org.springframework.web: INFO\n org.hibernate.SQL: DEBUG\n org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} - %msg%n\"\n file: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n file:\n name: logs/application.log\n max-size: 10MB\n max-history: 30\n\n# CORS配置\ncors:\n allowed-origins: http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000\n allowed-methods: GET,POST,PUT,DELETE,OPTIONS\n allowed-headers: \"*\"\n allow-credentials: true\n max-age: 3600\n\n# 应用信息\napp:\n name: AI智能学习导师\n version: 1.0.0\n description: 基于Spring Boot的AI智能学习助手\n storage:\n root-dir: ${APP_STORAGE_ROOT:./}\n cloud-disk-dir: ${CLOUD_DISK_DIR:cloud_disk}\n avatars-dir: ${AVATARS_DIR:avatars}\n cloud-disk:\n path: ./cloud_disk\n\n"}}}}