# newXinsi **Repository Path**: testing-category/new-xinsi ## Basic Information - **Project Name**: newXinsi - **Description**: 111111111111 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-06-15 - **Last Updated**: 2025-06-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 🤖 超级AI面试官 (Xinsi) 一个基于Spring Boot和AI技术的智能面试辅助平台,帮助求职者优化简历、准备面试、模拟面试流程。 ## 📋 目录 - [项目概览](#项目概览) - [技术栈](#技术栈) - [系统架构](#系统架构) - [快速开始](#快速开始) - [功能详解](#功能详解) - [API文档](#api文档) - [数据库设计](#数据库设计) - [执行流程](#执行流程) - [配置说明](#配置说明) - [部署指南](#部署指南) - [开发指南](#开发指南) ## 🎯 项目概览 ### 核心功能 - **智能对话**: 基于扣子(Coze) API的AI面试助手 - **简历优化**: AI驱动的简历分析和优化建议 - **面试模拟**: 技术面试、行为面试全方位模拟 - **文件分析**: 支持PDF、DOC、图片等多格式文件上传分析 - **会话管理**: 完整的聊天记录和会话历史 - **匿名体验**: 无需注册即可体验核心功能 ### 项目特色 - 🎨 **现代化UI**: 渐变设计、动画效果、响应式布局 - 🔐 **安全认证**: JWT Token + BCrypt密码加密 - 📁 **云端存储**: 阿里云OSS文件存储 - 🚀 **高性能**: MyBatis二级缓存、数据库优化 - 📱 **移动友好**: 适配多设备屏幕尺寸 ## 🛠️ 技术栈 ### 后端技术 - **框架**: Spring Boot 3.5.0 - **安全**: Spring Security + JWT - **数据库**: MySQL 8.0 + MyBatis 3.0.3 - **AI服务**: 扣子(Coze) API - **文件存储**: 阿里云OSS - **工具**: Lombok、HttpClient5 - **JDK**: Java 17 ### 前端技术 - **模板引擎**: Thymeleaf - **前端**: HTML5 + CSS3 + JavaScript ES6+ - **UI设计**: 原生CSS + 现代化渐变设计 ### 开发工具 - **构建工具**: Maven - **IDE**: IntelliJ IDEA / Eclipse - **版本控制**: Git ## 🏗️ 系统架构 ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 前端页面 │────│ Spring Boot │────│ MySQL │ │ (Thymeleaf) │ │ 后端服务 │ │ 数据库 │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ├─────────────────┐ │ │ ┌─────────────────┐ ┌─────────────────┐ │ 扣子API │ │ 阿里云OSS │ │ (AI服务) │ │ (文件存储) │ └─────────────────┘ └─────────────────┘ ``` ## 🚀 快速开始 ### 环境要求 - JDK 17+ - Maven 3.6+ - MySQL 8.0+ - Node.js 16+ (可选,用于前端开发) ### 安装步骤 1. **克隆项目** ```bash git clone https://github.com/your-username/xinsi.git cd xinsi ``` 2. **数据库配置** ```sql -- 创建数据库 CREATE DATABASE xinsi CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 导入数据表 mysql -u root -p xinsi < src/main/resources/sql/xinsi.sql ``` 3. **配置文件** ```yaml # 修改 src/main/resources/application.yml spring: datasource: url: jdbc:mysql://localhost:3306/xinsi?useSSL=false&serverTimezone=UTC username: your_username password: your_password # 配置阿里云OSS(可选) aliyun: oss: endpoint: https://oss-cn-beijing.aliyuncs.com accessKeyId: your_access_key_id accessKeySecret: your_access_key_secret bucketName: your_bucket_name ``` 4. **启动项目** ```bash mvn clean install mvn spring-boot:run ``` 5. **访问应用** - 主页: http://localhost:80 - 登录: http://localhost:80/login - 注册: http://localhost:80/register - AI聊天: http://localhost:80/chat ## 🎨 功能详解 ### 1. 用户管理系统 #### 用户注册流程 ```java // 注册流程图 用户输入信息 → 前端验证 → 后端验证 → 密码加密 → 数据库存储 → 注册成功 ``` **实现逻辑**: ```java @PostMapping("/register") public Map register(@RequestBody UserRegisterRequest request) { // 1. 参数验证 if (username.length() < 3 || username.length() > 20) { return error("用户名长度应在3-20个字符之间"); } // 2. 密码确认验证 if (!password.equals(request.getConfirmPassword())) { return error("两次输入的密码不一致"); } // 3. 唯一性检查 if (userService.isUsernameExists(username)) { return error("用户名已存在"); } // 4. 密码加密存储 String encodedPassword = passwordEncoder.encode(password); User user = new User(username, encodedPassword, email, phone); userMapper.insert(user); return success("注册成功"); } ``` #### JWT认证机制 ```java // JWT流程 登录成功 → 生成JWT Token → 返回给客户端 → 客户端存储 → 请求携带Token → 服务端验证 ``` ### 2. AI对话系统 #### 消息发送流程 ```mermaid graph TD A[用户发送消息] --> B{是否登录用户} B -->|是| C[保存到数据库] B -->|否| D[匿名模式] C --> E[调用Coze API] D --> E E --> F[获取AI回复] F --> G{是否登录用户} G -->|是| H[保存AI回复到数据库] G -->|否| I[直接返回] H --> J[返回给用户] I --> J ``` **核心实现**: ```java @PostMapping("/send") public ResponseEntity> sendMessage(@RequestBody Map request) { String message = request.get("message"); String username = request.get("username"); String aiResponse; if (username == null || "anonymous_user".equals(username)) { // 匿名用户:直接调用CozeAPI String cozeUserId = "anonymous_" + System.currentTimeMillis(); aiResponse = cozeApiService.sendMessage(message.trim(), cozeUserId); } else { // 登录用户:使用ChatService(包含数据库存储) aiResponse = chatService.sendMessage(username, message.trim()); } return ResponseEntity.ok(Map.of( "success", true, "message", aiResponse, "timestamp", System.currentTimeMillis() )); } ``` #### 会话管理逻辑 ```java // 会话创建流程 1. 用户发送第一条消息 2. 系统创建新会话记录 3. 生成唯一的CozeUserId用于上下文维持 4. 后续消息复用该会话ID 5. 会话标题自动生成(第一条消息的摘要) ``` ### 3. 文件上传系统 #### 文件处理流程 ```java // 文件上传流程 文件选择 → 类型验证 → 大小检查 → 上传到OSS → 获取文件URL → 发送给AI分析 ``` **支持格式**: - 文档: PDF, DOC, DOCX, TXT - 图片: JPG, PNG, GIF, BMP - 大小限制: 单文件10MB, 总计100MB **实现代码**: ```java @PostMapping("/send-with-file") public ResponseEntity> sendMessageWithFile( @RequestParam("message") String message, @RequestParam("username") String username, @RequestParam(value = "file", required = false) MultipartFile file) { // 1. 文件验证 if (file != null && !file.isEmpty()) { String contentType = file.getContentType(); if (!isValidFileType(contentType)) { return error("仅支持PDF、DOC、DOCX、TXT和图片格式"); } if (file.getSize() > 10 * 1024 * 1024) { return error("文件大小不能超过10MB"); } } // 2. 文件上传到OSS String fileUrl = cozeApiService.uploadFileToOSS(file); // 3. 发送消息给AI String aiResponse = cozeApiService.sendMessageWithFile(message, fileUrl, cozeUserId, null); return success(aiResponse); } ``` ## 📚 API文档 ### 用户管理API #### 用户注册 ```http POST /api/users/register Content-Type: application/json { "username": "testuser", "password": "password123", "confirmPassword": "password123", "email": "test@example.com", "phone": "13800138000" } ``` #### 用户登录 ```http POST /api/users/login Content-Type: application/json { "username": "testuser", "password": "password123" } ``` #### 检查用户名可用性 ```http GET /api/users/check-username?username=testuser ``` ### 聊天API #### 发送消息 ```http POST /chat/send Content-Type: application/json { "message": "你好,我想了解如何优化简历", "username": "testuser" } ``` #### 获取用户会话列表 ```http GET /chat/sessions?username=testuser ``` #### 获取会话消息 ```http GET /chat/sessions/{sessionId}/messages?page=1&size=50 ``` #### 删除会话 ```http DELETE /chat/sessions/{sessionId} ``` ## 🗄️ 数据库设计 ### 核心表结构 #### 用户表 (user) ```sql CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(255) NOT NULL COMMENT '密码(加密后)', `email` varchar(100) NOT NULL COMMENT '邮箱', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `avatar_url` varchar(255) DEFAULT NULL COMMENT '头像URL', `user_type` tinyint DEFAULT 1 COMMENT '用户类型:1-求职者,2-企业用户,3-管理员', `status` tinyint DEFAULT 1 COMMENT '状态:1-正常,0-禁用', `last_login_time` timestamp NULL DEFAULT NULL COMMENT '最后登录时间', `create_time` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`), UNIQUE KEY `email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` #### 聊天会话表 (chat_sessions) ```sql CREATE TABLE `chat_sessions` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '会话ID', `user_id` bigint NOT NULL COMMENT '用户ID', `title` varchar(100) NOT NULL COMMENT '会话标题', `status` tinyint DEFAULT 1 COMMENT '会话状态:1-活跃,0-已结束', `last_message_time` datetime NOT NULL COMMENT '最后一条消息时间', `create_time` datetime NOT NULL COMMENT '创建时间', `update_time` datetime NOT NULL COMMENT '更新时间', `message_count` int DEFAULT 0 COMMENT '消息总数', `coze_conversation_id` varchar(100) DEFAULT NULL COMMENT '扣子会话ID', `coze_user_id` varchar(100) DEFAULT NULL COMMENT '扣子用户ID', PRIMARY KEY (`id`), KEY `idx_user_id` (`user_id`), CONSTRAINT `chat_sessions_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` #### 聊天消息表 (chat_messages) ```sql CREATE TABLE `chat_messages` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '消息ID', `session_id` bigint NOT NULL COMMENT '会话ID', `user_id` bigint NOT NULL COMMENT '用户ID', `message_type` enum('user','ai') NOT NULL COMMENT '消息类型', `content` text NOT NULL COMMENT '消息内容', `status` tinyint DEFAULT 1 COMMENT '消息状态:1-正常,0-已删除', `create_time` datetime NOT NULL COMMENT '创建时间', `response_time` bigint DEFAULT NULL COMMENT 'AI响应时间(毫秒)', `coze_user_id` varchar(100) DEFAULT NULL COMMENT '扣子API的用户ID', PRIMARY KEY (`id`), KEY `idx_session_id` (`session_id`), KEY `idx_user_id` (`user_id`), FULLTEXT KEY `idx_content` (`content`), CONSTRAINT `chat_messages_ibfk_1` FOREIGN KEY (`session_id`) REFERENCES `chat_sessions` (`id`) ON DELETE CASCADE, CONSTRAINT `chat_messages_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 数据库特性 - **外键约束**: 确保数据一致性 - **索引优化**: 提高查询性能 - **全文搜索**: 支持消息内容搜索 - **软删除**: 支持数据恢复 - **统计视图**: 用户聊天统计 - **清理存储过程**: 自动清理历史数据 ## 🔄 执行流程 ### 1. 用户注册完整流程 ```mermaid sequenceDiagram participant U as 用户 participant F as 前端 participant B as 后端 participant DB as 数据库 U->>F: 填写注册信息 F->>F: 客户端表单验证 F->>B: 发送注册请求 B->>B: 服务端参数验证 B->>DB: 检查用户名是否存在 DB-->>B: 返回检查结果 B->>DB: 检查邮箱是否存在 DB-->>B: 返回检查结果 B->>B: 密码加密(BCrypt) B->>DB: 插入用户记录 DB-->>B: 返回插入结果 B-->>F: 返回注册结果 F-->>U: 显示注册成功/失败 ``` ### 2. AI对话完整流程 ```mermaid sequenceDiagram participant U as 用户 participant F as 前端 participant B as 后端 participant DB as 数据库 participant AI as Coze API participant OSS as 阿里云OSS U->>F: 发送消息/上传文件 F->>B: 请求到ChatController alt 有文件上传 B->>OSS: 上传文件 OSS-->>B: 返回文件URL end alt 登录用户 B->>DB: 创建/获取会话 DB-->>B: 返回会话信息 B->>DB: 保存用户消息 end B->>AI: 调用Coze API AI-->>B: 返回AI回复 alt 登录用户 B->>DB: 保存AI回复 B->>DB: 更新会话信息 end B-->>F: 返回AI回复 F-->>U: 显示AI回复 ``` ### 3. 文件上传处理流程 ```mermaid flowchart TD A[用户选择文件] --> B{文件类型验证} B -->|不支持| C[显示错误信息] B -->|支持| D{文件大小检查} D -->|超过限制| E[显示大小错误] D -->|符合要求| F[上传到阿里云OSS] F --> G{上传成功?} G -->|失败| H[显示上传失败] G -->|成功| I[获取文件URL] I --> J[发送消息到AI] J --> K[返回AI分析结果] ``` ## ⚙️ 配置说明 ### application.yml 核心配置 ```yaml server: port: 80 # 服务端口 servlet: context-path: / # 上下文路径 spring: # 数据库配置 datasource: url: jdbc:mysql://localhost:3306/xinsi?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8 username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver # Thymeleaf配置 thymeleaf: cache: false # 开发环境禁用缓存 encoding: UTF-8 mode: HTML # 文件上传配置 servlet: multipart: max-file-size: 10MB max-request-size: 100MB # MyBatis配置 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: icu.cqcai.xinsi.domain configuration: map-underscore-to-camel-case: true cache-enabled: true lazy-loading-enabled: true # JWT配置 jwt: secret: your-secret-key-here # 至少64个字符 expiration: 86400000 # 24小时 token-prefix: "Bearer " header-name: "Authorization" # 阿里云OSS配置 aliyun: oss: endpoint: https://oss-cn-beijing.aliyuncs.com accessKeyId: your-access-key-id accessKeySecret: your-access-key-secret bucketName: your-bucket-name ``` ### 环境变量配置 ```bash # 生产环境建议使用环境变量 export DB_PASSWORD=your_db_password export JWT_SECRET=your_jwt_secret export OSS_ACCESS_KEY_ID=your_oss_access_key_id export OSS_ACCESS_KEY_SECRET=your_oss_access_key_secret ``` ## 🚀 部署指南 ### Docker部署 1. **创建Dockerfile** ```dockerfile FROM openjdk:17-jdk-slim WORKDIR /app COPY target/xinsi-0.0.1-SNAPSHOT.jar app.jar EXPOSE 80 ENTRYPOINT ["java", "-jar", "app.jar"] ``` 2. **构建和运行** ```bash # 构建JAR包 mvn clean package -DskipTests # 构建Docker镜像 docker build -t xinsi:latest . # 运行容器 docker run -d -p 80:80 --name xinsi-app xinsi:latest ``` ### 生产环境部署 1. **服务器配置** ```bash # 安装Java 17 sudo apt update sudo apt install openjdk-17-jdk # 安装MySQL sudo apt install mysql-server # 创建应用用户 sudo useradd -m -s /bin/bash xinsi ``` 2. **应用部署** ```bash # 创建应用目录 sudo mkdir -p /opt/xinsi sudo chown xinsi:xinsi /opt/xinsi # 复制JAR包 sudo cp target/xinsi-0.0.1-SNAPSHOT.jar /opt/xinsi/ # 创建启动脚本 sudo tee /opt/xinsi/start.sh << EOF #!/bin/bash java -jar -Xmx512m -Xms256m /opt/xinsi/xinsi-0.0.1-SNAPSHOT.jar EOF sudo chmod +x /opt/xinsi/start.sh ``` 3. **系统服务配置** ```bash # 创建systemd服务 sudo tee /etc/systemd/system/xinsi.service << EOF [Unit] Description=Xinsi AI Interview Assistant After=network.target [Service] Type=simple User=xinsi ExecStart=/opt/xinsi/start.sh Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF # 启动服务 sudo systemctl daemon-reload sudo systemctl enable xinsi sudo systemctl start xinsi ``` ### Nginx反向代理 ```nginx server { listen 80; server_name your-domain.com; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 静态资源缓存 location ~* \.(css|js|img|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; proxy_pass http://localhost:8080; } } ``` ## 👨‍💻 开发指南 ### 项目结构 ``` src/ ├── main/ │ ├── java/ │ │ └── icu/cqcai/xinsi/ │ │ ├── config/ # 配置类 │ │ ├── controller/ # 控制器 │ │ ├── domain/ # 实体类 │ │ │ └── dto/ # 数据传输对象 │ │ ├── mapper/ # MyBatis映射器 │ │ ├── service/ # 服务层 │ │ │ └── impl/ # 服务实现 │ │ └── util/ # 工具类 │ └── resources/ │ ├── mapper/ # MyBatis XML映射文件 │ ├── sql/ # 数据库脚本 │ ├── static/ # 静态资源 │ ├── templates/ # Thymeleaf模板 │ └── application.yml # 应用配置 ``` ### 开发规范 #### 代码规范 ```java // 1. 类名使用Pascal命名法 public class UserService {} // 2. 方法名使用camelCase public void getUserById() {} // 3. 常量使用UPPER_SNAKE_CASE public static final String DEFAULT_USER_AVATAR = "default_avatar.png"; // 4. 使用有意义的变量名 String userEmail = request.getEmail(); // 好 String e = request.getEmail(); // 差 // 5. 方法注释 /** * 根据用户名查找用户 * @param username 用户名 * @return 用户对象,如果不存在返回null */ public User findByUsername(String username) {} ``` #### 异常处理 ```java @PostMapping("/api/users/register") public ResponseEntity> register(@RequestBody UserRegisterRequest request) { try { String result = userService.register(request); return ResponseEntity.ok(Map.of("success", true, "message", result)); } catch (BusinessException e) { return ResponseEntity.badRequest().body(Map.of("success", false, "message", e.getMessage())); } catch (Exception e) { logger.error("用户注册失败", e); return ResponseEntity.internalServerError().body(Map.of("success", false, "message", "系统错误")); } } ``` #### 日志规范 ```java // 使用SLF4J private static final Logger logger = LoggerFactory.getLogger(UserService.class); // 日志级别使用 logger.debug("用户注册请求: {}", request); // 调试信息 logger.info("用户注册成功: {}", username); // 重要信息 logger.warn("用户名已存在: {}", username); // 警告信息 logger.error("数据库操作失败", e); // 错误信息 ``` ### 测试指南 #### 单元测试 ```java @SpringBootTest class UserServiceTest { @Autowired private UserService userService; @Test void testRegisterSuccess() { UserRegisterRequest request = new UserRegisterRequest(); request.setUsername("testuser"); request.setPassword("password123"); request.setConfirmPassword("password123"); request.setEmail("test@example.com"); String result = userService.register(request); assertEquals("注册成功", result); } @Test void testRegisterDuplicateUsername() { // 测试用户名重复的情况 UserRegisterRequest request = new UserRegisterRequest(); request.setUsername("existinguser"); String result = userService.register(request); assertEquals("用户名已存在", result); } } ``` #### 集成测试 ```java @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class UserControllerIntegrationTest { @Autowired private TestRestTemplate restTemplate; @Test void testRegisterEndpoint() { UserRegisterRequest request = new UserRegisterRequest(); // 设置请求数据... ResponseEntity response = restTemplate.postForEntity( "/api/users/register", request, Map.class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue((Boolean) response.getBody().get("success")); } } ``` ### 性能优化 #### 数据库优化 ```sql -- 1. 添加索引 CREATE INDEX idx_username ON user(username); CREATE INDEX idx_session_user_id ON chat_sessions(user_id); CREATE INDEX idx_message_session_id ON chat_messages(session_id); -- 2. 查询优化 SELECT * FROM chat_messages WHERE session_id = ? ORDER BY create_time DESC LIMIT 50; -- 3. 批量插入 INSERT INTO chat_messages (session_id, user_id, message_type, content, create_time) VALUES (?, ?, ?, ?, ?), (?, ?, ?, ?, ?), (?, ?, ?, ?, ?); ``` #### 缓存策略 ```java @Service public class UserService { @Cacheable(value = "users", key = "#username") public User findByUsername(String username) { return userMapper.findByUsername(username); } @CacheEvict(value = "users", key = "#user.username") public void updateUser(User user) { userMapper.update(user); } } ``` ## 🐛 常见问题 ### 1. 数据库连接问题 ``` 错误: Communications link failure 解决: 检查MySQL服务状态,确认连接参数正确 ``` ### 2. JWT Token过期 ``` 错误: JWT token expired 解决: 前端检查token有效期,自动刷新或重新登录 ``` ### 3. 文件上传失败 ``` 错误: MultipartException: Maximum upload size exceeded 解决: 调整spring.servlet.multipart.max-file-size配置 ``` ### 4. 跨域问题 ``` 错误: CORS policy: No 'Access-Control-Allow-Origin' header 解决: 添加@CrossOrigin注解或配置全局CORS ``` ## 📈 监控与运维 ### 性能监控 ```yaml management: endpoints: web: exposure: include: health,info,metrics endpoint: health: show-details: always ``` ### 日志管理 ```yaml logging: level: icu.cqcai.xinsi: DEBUG org.springframework.security: DEBUG pattern: file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" file: name: logs/xinsi.log max-size: 100MB max-history: 30 ``` ## 🤝 贡献指南 1. Fork 项目 2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) 3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) 4. 推送到分支 (`git push origin feature/AmazingFeature`) 5. 开启 Pull Request ## 📄 许可证 本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详细信息。 ## 📞 联系方式 - 项目地址: https://github.com/your-username/xinsi - 邮箱: your-email@example.com - 文档: https://your-docs-site.com --- **⭐ 如果这个项目对您有帮助,请给我们一个星标!**