三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Java+SSM与Flask混合架构教学平台开发实践

Java+SSM与Flask混合架构教学平台开发实践

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 多格式课件在线预览方案

文件处理流程:

  1. 用户上传文件到MinIO对象存储
  2. Flask服务监听存储桶事件
  3. 根据文件类型调用不同处理器:
    • 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 高并发下载解决方案

遇到的问题:

  • 热门课件下载导致服务器带宽打满
  • 数据库连接池耗尽

最终方案:

  1. 七牛云CDN静态资源加速
  2. 下载请求限流(Guava RateLimiter)
  3. 异步记录下载日志
// 下载限流实现 @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 缓存策略设计

多级缓存架构:

  1. 本地Caffeine缓存(高频访问数据)
    • 课程基本信息
    • 用户权限数据
  2. Redis集群缓存(分布式共享数据)
    • 热门课件列表
    • 实时排行榜数据
  3. 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看板包含:

  1. 实时在线人数
  2. 资源下载速度趋势
  3. API响应时间百分位图
  4. 异常请求TOP10统计

6. 典型问题排查手册

6.1 跨域会话丢失问题

现象:Flask服务获取不到Java端设置的Cookie

解决方案:

  1. 明确设置Cookie域和路径
Cookie cookie = new Cookie("sessionid", token); cookie.setDomain(".yourdomain.com"); cookie.setPath("/"); cookie.setHttpOnly(true); response.addCookie(cookie);
  1. 配置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分钟

优化后方案:

  1. 使用BatchExecutor
  2. 改写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>
  1. 添加rewriteBatchedStatements=true参数

优化效果:10万条数据插入从6分钟降至8秒

7. 安全防护实践

7.1 课件下载权限控制

实现方案:

  1. 动态链接签名(HMAC-SHA256)
  2. 时效性控制(5分钟有效期)
  3. 下载次数限制(单个链接最大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防护策略

多层次防护:

  1. 前端:DOMPurify过滤HTML
  2. 后端:Jackson自定义转义
@Bean public Jackson2ObjectMapperBuilder objectMapperBuilder() { return new Jackson2ObjectMapperBuilder() .defaultHtmlEscaping(true) .serializers(new StringUnicodeSerializer()); }
  1. 数据库:存储前内容清洗

8. 项目演进方向

当前正在实施的改进:

  1. 引入Elasticsearch实现全文检索
  2. 基于OpenCV开发课件图片OCR功能
  3. 使用Kubernetes实现自动扩缩容

技术债务清单:

  • 需要重构的模块:积分系统耦合度过高
  • 待优化的查询:学习轨迹分析SQL
  • 计划替换的组件:从MinIO迁移到阿里云OSS
← 返回列表