1. 项目概述:Java+SSM+Flask混合架构教学平台开发实录
这个项目是我去年为本地一所职业院校开发的课程辅助教学系统,采用Java+SSM作为后端核心,Flask处理轻量级服务,前后端分离架构。平台上线后日均访问量稳定在2000+,成功承载了12门专业课的在线教学任务。不同于常见的单一技术栈方案,这种混合架构既发挥了Java企业级开发的稳定性优势,又利用了Python在数据处理方面的灵活性。
关键数据:系统峰值QPS达到380,课程资源库累计存储2.3TB教学资料,支持5种主流文档格式在线预览
2. 技术选型与架构设计
2.1 为什么选择SSM+Flask混合架构
SSM(Spring+SpringMVC+MyBatis)作为主框架处理核心业务逻辑:
- Spring 5.2.6:IoC容器管理Bean生命周期
- SpringMVC:RESTful接口设计,Content Negotiation处理多种数据格式
- MyBatis 3.5.6:二级缓存+自定义TypeHandler优化数据库操作
Flask 1.1.2负责专项服务:
- 文件内容提取(PDF/Word/PPT文本抽取)
- 简单数据分析(学习行为统计)
- 定时任务调度(课件自动归档)
// SSM中集成Flask服务的典型调用示例 @RestController @RequestMapping("/api/document") public class DocController { @Autowired private RestTemplate restTemplate; @GetMapping("/preview/{fileId}") public ResponseEntity<byte[]> previewDocument(@PathVariable String fileId) { // 调用Flask文档预处理服务 String flaskUrl = "http://flask-service:5000/preview?id=" + fileId; return restTemplate.exchange(flaskUrl, HttpMethod.GET, null, byte[].class); } }2.2 数据库设计要点
MySQL 8.0主从架构设计:
- 主库:写操作+核心业务表
- course_info(课程基础信息)
- chapter_structure(章节树形结构)
- 从库:读密集型操作
- resource_download(资源下载记录)
- qa_interaction(问答数据)
-- 课程章节表的递归CTE查询设计 CREATE TABLE `course_chapter` ( `chapter_id` BIGINT PRIMARY KEY, `course_id` BIGINT NOT NULL, `parent_id` BIGINT DEFAULT NULL, `chapter_name` VARCHAR(100) NOT NULL, `sort_order` INT DEFAULT 0, FOREIGN KEY (`parent_id`) REFERENCES `course_chapter` (`chapter_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;3. 核心功能实现细节
3.1 多格式课件在线预览方案
文件处理流程:
- 用户上传文件到MinIO对象存储
- Flask服务监听存储桶事件
- 根据文件类型调用不同处理器:
- PDF:PyPDF2提取文本+pdf.js前端渲染
- Office:python-pptx/docx库转换HTML
- 视频:FFmpeg生成HLS分片
# Flask中的文件处理器示例 @app.route('/convert', methods=['POST']) def convert_file(): file = request.files['file'] file_type = file.filename.split('.')[-1].lower() if file_type == 'pdf': with tempfile.NamedTemporaryFile() as tmp: file.save(tmp.name) text = extract_pdf_text(tmp.name) return jsonify({'text': text}) elif file_type in ['docx', 'doc']: return convert_word_to_html(file) else: abort(415, description="Unsupported media type")3.2 实时问答系统实现
技术组合:
- WebSocket协议维持长连接
- Redis Pub/Sub处理消息广播
- MySQL存储问答持久化数据
// SSM中的WebSocket配置 @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(qaSocketHandler(), "/qa") .setAllowedOrigins("*") .addInterceptors(new HttpSessionHandshakeInterceptor()); } @Bean public QASocketHandler qaSocketHandler() { return new QASocketHandler(); } }4. 性能优化实战记录
4.1 高并发下载解决方案
遇到的问题:
- 热门课件下载导致服务器带宽打满
- 数据库连接池耗尽
最终方案:
- 七牛云CDN静态资源加速
- 下载请求限流(Guava RateLimiter)
- 异步记录下载日志
// 下载限流实现 @RestController @RequestMapping("/download") public class DownloadController { private final RateLimiter rateLimiter = RateLimiter.create(100.0); // 每秒100个令牌 @GetMapping("/resource/{id}") public ResponseEntity<Resource> downloadResource(@PathVariable String id) { if (!rateLimiter.tryAcquire()) { throw new RateLimitExceededException(); } // ...实际下载逻辑 } }4.2 缓存策略设计
多级缓存架构:
- 本地Caffeine缓存(高频访问数据)
- 课程基本信息
- 用户权限数据
- Redis集群缓存(分布式共享数据)
- 热门课件列表
- 实时排行榜数据
- MySQL查询缓存(复杂查询结果)
缓存更新策略:
- 课程信息:TTL 30分钟 + 修改时主动失效
- 排行榜数据:定时任务每5分钟更新
5. 部署与监控方案
5.1 容器化部署架构
Docker Compose编排方案:
version: '3.8' services: mysql-master: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS} ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql flask-service: build: ./flask ports: - "5000:5000" depends_on: - redis java-app: build: ./java ports: - "8080:8080" depends_on: - mysql-master - redis volumes: mysql-data:5.2 监控指标配置
Prometheus监控重点:
- JVM指标(GC次数、堆内存)
- MySQL连接池使用率
- Flask服务响应时间
- 接口成功率(5xx错误率)
Grafana看板包含:
- 实时在线人数
- 资源下载速度趋势
- API响应时间百分位图
- 异常请求TOP10统计
6. 典型问题排查手册
6.1 跨域会话丢失问题
现象:Flask服务获取不到Java端设置的Cookie
解决方案:
- 明确设置Cookie域和路径
Cookie cookie = new Cookie("sessionid", token); cookie.setDomain(".yourdomain.com"); cookie.setPath("/"); cookie.setHttpOnly(true); response.addCookie(cookie);- 配置CORS过滤器
@Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("https://frontend.yourdomain.com"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); }6.2 MyBatis批量插入优化
原始方案问题:万级数据插入耗时超过10分钟
优化后方案:
- 使用BatchExecutor
- 改写Mapper配置
<insert id="batchInsert" parameterType="java.util.List"> INSERT INTO download_log (user_id, resource_id, create_time) VALUES <foreach collection="list" item="item" separator=","> (#{item.userId}, #{item.resourceId}, #{item.createTime}) </foreach> </insert>- 添加rewriteBatchedStatements=true参数
优化效果:10万条数据插入从6分钟降至8秒
7. 安全防护实践
7.1 课件下载权限控制
实现方案:
- 动态链接签名(HMAC-SHA256)
- 时效性控制(5分钟有效期)
- 下载次数限制(单个链接最大3次)
public String generateDownloadUrl(Long resourceId) { long timestamp = System.currentTimeMillis(); String raw = resourceId + "|" + timestamp + "|" + SECRET_SALT; String sign = HmacUtils.hmacSha256Hex(API_SECRET, raw); return String.format("/download?res=%d&t=%d&s=%s", resourceId, timestamp, sign); }7.2 XSS防护策略
多层次防护:
- 前端:DOMPurify过滤HTML
- 后端:Jackson自定义转义
@Bean public Jackson2ObjectMapperBuilder objectMapperBuilder() { return new Jackson2ObjectMapperBuilder() .defaultHtmlEscaping(true) .serializers(new StringUnicodeSerializer()); }- 数据库:存储前内容清洗
8. 项目演进方向
当前正在实施的改进:
- 引入Elasticsearch实现全文检索
- 基于OpenCV开发课件图片OCR功能
- 使用Kubernetes实现自动扩缩容
技术债务清单:
- 需要重构的模块:积分系统耦合度过高
- 待优化的查询:学习轨迹分析SQL
- 计划替换的组件:从MinIO迁移到阿里云OSS