news 2026/9/1 22:58:20

SpringBoot整合AI大模型:影视评论舆情分析与可视化平台实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot整合AI大模型:影视评论舆情分析与可视化平台实战

大家好,我是老K。又是一年毕业设计季,每年这个时候,总有不少同学在后台问我:“SpringBoot 选题太普通怎么办?”“前端 + 后端做了个管理系统,答辩时怎么讲出亮点?”

如果你也有同样的焦虑,那今天这篇文章应该能帮上忙。我围绕一个非常典型的毕设项目——“SpringBoot + AI大模型影视评论舆情分析可视化平台”,完整拆解整个项目的技术架构、核心代码、数据库设计、AI 大模型如何接入、数据可视化如何落地,以及答辩时的高频问题。

需要提前说明的是:这个项目虽然是用“影视评论”作为业务场景,但整体架构完全可以迁移到电商评论、旅游点评、新闻评论、社交舆情等任何文本舆情分析场景。读完本文,你不仅能做出一个能运行的毕设项目,更能理解背后的技术链路:数据采集 → 数据清洗 → AI 情感分析 → 数据落库 → 可视化展示。

1. 项目背景与核心概念

1.1 为什么选“影视评论舆情分析”这个方向

做毕设选题时,最重要的原则是:业务场景贴近生活,技术栈有展示空间

影视评论(豆瓣短评、猫眼评论、微博影评等)天然具有以下特点:

  • 数据量可观:一部热门电影的评论数量轻松破万,天然构成“大数据”场景。
  • 文本内容丰富:用户评论包含情感倾向(好评/差评)、话题焦点(剧情、演技、特效、配乐)、多样表达方式。
  • 分析价值明显:通过舆情分析,可以判断一部电影的公众口碑走向、热度趋势、负面焦点。
  • 展示效果好:饼图、折线图、词云图、情感分布图……可视化维度非常多。

对于毕业设计答辩来说,这个项目可以从“数据采集→后端接口→AI分析→可视化展示”形成完整闭环,每个环节都有东西可讲。

1.2 系统整体技术架构

本项目的核心架构可以用一句话概括:“前端展示 + 后端服务 + AI 分析引擎 + 数据存储”四层结构

层次技术选型职责
前端展示层Vue.js + ECharts数据可视化、舆情看板、交互管理
后端服务层Spring Boot 2.x / 3.x提供 RESTful API、业务逻辑、认证鉴权
AI 分析层大模型 API 调用(文本情感分析、关键词抽取)对评论文本进行情感判断和主题抽取
数据存储层MySQL + Redis持久化影视数据、评论数据、分析结果;缓存高频查询

1.3 功能模块划分

整个平台围绕“舆情分析”这个核心,拆分为以下功能模块:

  1. 影视信息管理:影片名称、导演、演员、上映时间、类型、地区等基础信息维护。
  2. 评论数据采集:通过爬虫或外部数据导入方式获取影视评论原始数据。
  3. AI 情感分析引擎:调用大模型接口,对每一条评论进行情感极性判断(正向/中性/负向)和情感分值输出。
  4. 舆情可视化看板
    • 评论数量趋势图(折线图)
    • 情感分布占比(饼图)
    • 高频关键词词云
    • 评分与评论数排行(柱状图)
    • 负面评论明细列表
  5. 系统管理:用户登录、角色权限、操作日志。

注意:爬虫模块在毕设中要严格遵守合法合规要求。建议使用公开数据集或官方开放 API(如豆瓣官方 API、IMDb 开放数据)作为数据来源,不要大规模爬取受版权保护的完整评论内容,更不要将爬取数据用于商业用途。

2. 环境准备与版本说明

2.1 开发环境总览

下面是本文推荐的一组稳定环境组合。你本机的版本不一定完全一致,但思路相同,重点是理解配置过程:

工具推荐版本说明
JDK1.8 或 11Spring Boot 2.x 使用 JDK 8+,Spring Boot 3.x 需要 JDK 17+
Maven3.6+依赖管理和项目构建
Spring Boot2.7.x 或 3.x根据 JDK 版本选择
MySQL5.7 / 8.0数据存储
Redis5.x+缓存,加速热点数据查询
Vue2.x / 3.x前端框架
ECharts5.x数据可视化图表库
开发工具IntelliJ IDEA / VSCode后端和前端开发

2.2 如何选择 Spring Boot 版本

很多同学在这个地方容易踩坑。Spring Boot 版本不是越高越好,取决于你的 JDK 版本

  • 如果你本机安装的是JDK 8,那么请使用Spring Boot 2.7.x,这是最后一个支持 JDK 8 的 2.x 版本。
  • 如果你安装的是JDK 17或更高版本,可以使用Spring Boot 3.x,但要注意部分第三方依赖(如 MyBatis 老版本、某些网上的封装工具类)可能不兼容。

本项目以 Spring Boot 2.7.x 为例进行说明。如果你的环境是 Spring Boot 3.x,主要差异集中在 Jakarta 命名空间(javax → jakarta),代码中涉及的地方我会特别标注。

<!-- pom.xml 中 Spring Boot 父依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath/> </parent>

2.3 项目结构规划

后端采用经典的分层架构,包结构如下:

com.example.movieanalysis ├── MovieAnalysisApplication.java # 启动类 ├── common/ # 通用工具、常量、统一返回 │ ├── Result.java │ └── ResultCode.java ├── config/ # 配置类 ├── controller/ # 控制层 │ ├── MovieController.java │ ├── CommentController.java │ ├── AnalysisController.java │ └── UserController.java ├── service/ # 业务层 │ ├── MovieService.java │ ├── CommentService.java │ ├── AnalysisService.java │ └── AiAnalysisService.java ├── mapper/ # MyBatis 数据访问层 ├── entity/ # 实体类 └── dto/ # 数据传输对象

3. 数据库设计与核心表结构

3.1 数据库设计原则

舆情分析平台的数据表设计需要考虑三个核心问题:

  1. 存储什么:影视基本信息、评论原文、AI 分析后的情感结果。
  2. 查询什么:按电影 ID 查评论、按日期统计评论量、按情感值分组统计。
  3. 如何关联:评论表通过 movie_id 关联电影表。

3.2 核心表结构

电影信息表 t_movie

CREATE TABLE `t_movie` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `movie_name` varchar(200) NOT NULL COMMENT '电影名称', `director` varchar(100) DEFAULT NULL COMMENT '导演', `actors` varchar(500) DEFAULT NULL COMMENT '主演,逗号分隔', `genres` varchar(100) DEFAULT NULL COMMENT '类型,如:动作/科幻', `release_date` date DEFAULT NULL COMMENT '上映日期', `rating` decimal(3,1) DEFAULT NULL COMMENT '平台评分', `cover_url` varchar(500) DEFAULT NULL COMMENT '海报URL', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='电影信息表';

评论信息表 t_comment

CREATE TABLE `t_comment` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `movie_id` bigint(20) NOT NULL COMMENT '关联电影ID', `user_name` varchar(100) DEFAULT NULL COMMENT '评论用户', `content` text COMMENT '评论内容', `comment_date` datetime DEFAULT NULL COMMENT '评论日期', `source` varchar(50) DEFAULT NULL COMMENT '来源平台:douban/maoyan/weibo', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_movie_id` (`movie_id`), KEY `idx_comment_date` (`comment_date`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='评论信息表';

情感分析结果表 t_sentiment_analysis

CREATE TABLE `t_sentiment_analysis` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `comment_id` bigint(20) NOT NULL COMMENT '关联评论ID', `sentiment_label` varchar(20) DEFAULT NULL COMMENT '情感标签:positive/neutral/negative', `sentiment_score` decimal(5,4) DEFAULT NULL COMMENT '情感分值,范围0~1,越接近1越正向', `ai_model` varchar(100) DEFAULT NULL COMMENT '使用的大模型名称', `analysis_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_comment_id` (`comment_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='AI情感分析结果表';

用户表 t_user

CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(255) NOT NULL COMMENT '密码,BCrypt加密', `role` varchar(20) DEFAULT 'USER' COMMENT '角色:ADMIN/USER', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='系统用户表';

这里有一个非常重要的设计细节:为什么情感分析结果单独拆一张表,而不是直接加到 t_comment 表中?

两个原因:

  1. 解耦:AI 分析结果可能会因为模型升级而重新生成,独立表方便重新跑批。
  2. 性能:评论表本身已经很大,如果每条评论附带多个分析字段,查询统计时会变慢。

4. AI 大模型接入与情感分析实现

4.1 大模型在舆情分析中的角色

在传统的舆情分析项目中,情感分析通常使用基于词典的方法(SnowNLP、BosonNLP)或者训练一个简单的文本分类模型。但这些方式在新领域、口语化表达、反讽等场景下准确率有限。

引入 AI 大模型后,核心优势在于:

  • 零样本或少样本学习:不需要标注大量训练语料,直接通过提示词让模型输出情感判断。
  • 语义理解能力强:能识别“绝了”“拴Q”“YYDS”等网络用语的真实情感倾向。
  • 支持批量分析:可以将多条评论拼接为 Prompt 批量提交,减少 API 调用次数。

4.2 大模型 API 接入通用实现

无论是接入国内大模型(文心一言、通义千问、智谱 GLM、DeepSeek)还是国外模型,调用流程基本都是:

  1. 注册账户,获取 API Key。
  2. 构造 HTTP 请求,携带 Prompt 文本。
  3. 解析模型返回的 JSON 响应。
  4. 将结果映射为业务对象。

下面给出一个通用的AiAnalysisService实现。这里以 OpenAI 兼容接口为例,国内大多数模型都提供兼容格式,你只需要替换apiKeybaseUrlmodel三个配置即可。

// 文件路径:src/main/java/com/example/movieanalysis/service/AiAnalysisService.java @Service public class AiAnalysisService { @Value("${ai.api-key}") private String apiKey; @Value("${ai.base-url}") private String baseUrl; @Value("${ai.model}") private String model; private static final Logger log = LoggerFactory.getLogger(AiAnalysisService.class); /** * 分析单条评论的情感倾向 * @param content 评论文本 * @return 情感分析结果 */ public SentimentResult analyzeSentiment(String content) { if (StringUtils.isBlank(content)) { return SentimentResult.neutral(); } // 1. 构造 Prompt String prompt = buildPrompt(content); // 2. 调用大模型 API String response = callAiApi(prompt); // 3. 解析返回结果 return parseResponse(response); } private String buildPrompt(String content) { return "你是一名影视评论情感分析专家。请分析下面这条电影评论的情感倾向," + "输出JSON格式:{\"sentiment\": \"positive|neutral|negative\", \"score\": 0.0~1.0}\n\n" + "评论内容:" + content; } private String callAiApi(String prompt) { // 构造请求体 Map<String, Object> requestBody = new HashMap<>(); requestBody.put("model", model); requestBody.put("messages", List.of( Map.of("role", "user", "content", prompt) )); requestBody.put("temperature", 0.0); try { String jsonBody = new ObjectMapper().writeValueAsString(requestBody); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setBearerAuth(apiKey); HttpEntity<String> request = new HttpEntity<>(jsonBody, headers); RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> response = restTemplate.exchange( baseUrl + "/chat/completions", HttpMethod.POST, request, String.class ); return response.getBody(); } catch (Exception e) { log.error("调用AI接口失败,评论内容: {}", content, e); // 降级:返回中性结果 return "{\"sentiment\": \"neutral\", \"score\": 0.5}"; } } private SentimentResult parseResponse(String response) { try { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(response); String content = root.path("choices").get(0).path("message").path("content").asText(); JsonNode analysis = mapper.readTree(cleanJsonContent(content)); return new SentimentResult(analysis.path("sentiment").asText(), analysis.path("score").asDouble()); } catch (Exception e) { log.error("解析AI返回结果失败: {}", response, e); return SentimentResult.neutral(); } } private String cleanJsonContent(String content) { // 有些模型会输出 ```json ``` 代码块标记,需要清理 return content.replace("```json", "").replace("```", "").trim(); } }

对应的配置项,在application.yml中:

ai: api-key: your-api-key-here base-url: https://api.example.com/v1 model: your-model-name

这里强调一下:不同大模型厂商的 API 地址和请求格式可能不同,示例代码是 OpenAI 兼容格式。实际接入时,以你选择的服务商文档为准。不要把 API Key 写在代码里提交到 GitHub,建议通过环境变量或配置文件外部化管理。

4.3 批量分析评论数据

单条评论逐个调用大模型接口效率太低,实际项目中推荐批量处理:

  • 将多条评论拼接到一个 Prompt 中,让模型一次性返回数组。
  • 使用线程池并发调用,控制 QPS 避免触发限流。
  • 已分析的评论记录分析状态,避免重复调用浪费成本。
// 批量分析实现,使用线程池并发处理 @Component public class BatchAnalysisService { private final AiAnalysisService aiAnalysisService; private final CommentMapper commentMapper; private final SentimentMapper sentimentMapper; // 自定义线程池,根据实际情况调整参数 private final ExecutorService executor = Executors.newFixedThreadPool(8); public void batchAnalyzeByMovie(Long movieId) { List<Comment> comments = commentMapper.selectByMovieId(movieId); CountDownLatch latch = new CountDownLatch(comments.size()); for (Comment comment : comments) { executor.submit(() -> { try { // 1. 调用AI分析 SentimentResult result = aiAnalysisService.analyzeSentiment(comment.getContent()); // 2. 保存结果 SentimentAnalysis analysis = new SentimentAnalysis(); analysis.setCommentId(comment.getId()); analysis.setSentimentLabel(result.getSentiment()); analysis.setSentimentScore(result.getScore()); analysis.setAiModel("your-model-name"); sentimentMapper.insert(analysis); // 3. 更新评论状态 commentMapper.updateAnalysisStatus(comment.getId(), 1); } catch (Exception e) { log.error("评论{}分析失败", comment.getId(), e); } finally { latch.countDown(); } }); } try { latch.await(10, TimeUnit.MINUTES); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }

4.4 AI 接入的降级兜底策略

在毕设答辩演示时,最怕出现“AI 接口超时、key 额度用尽”导致系统直接报错。这里给大家一个非常重要的实战经验:AI 接口必须做降级处理

建议方案:

  1. 本地词典预判:先用 SnowNLP 或自建情感词典跑一遍分数,大模型接口失败时直接返回本地结果。
  2. 缓存结果:同一评论文本的 AI 分析结果放入 Redis,重复请求不重复调用 API。
  3. 失败重试 + 熔断:连续失败 3 次后,直接熔断并转向本地分析。

5. 后端接口设计与业务实现

5.1 统一返回结果封装

为了前后端数据交互规范,后端所有接口统一返回Result<T>结构。

// 文件路径:src/main/java/com/example/movieanalysis/common/Result.java public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage("success"); result.setData(data); return result; } public static <T> Result<T> error(Integer code, String message) { Result<T> result = new Result<>(); result.setCode(code); result.setMessage(message); return result; } // getter/setter 省略 }

5.2 舆情统计接口

这是整个系统最核心的接口。前端看板页面需要展示以下数据:

  • 某部电影的整体评论数、均值情感分数。
  • 日期维度的评论量趋势。
  • 情感分布占比。

对应接口设计如下:

// 文件路径:src/main/java/com/example/movieanalysis/controller/AnalysisController.java @RestController @RequestMapping("/api/analysis") public class AnalysisController { @Resource private AnalysisService analysisService; /** * 按电影ID获取舆情看板统计信息 */ @GetMapping("/overview/{movieId}") public Result<OverviewVO> getOverview(@PathVariable Long movieId) { return Result.success(analysisService.getOverview(movieId)); } /** * 按电影ID获取评论趋势(按天统计) */ @GetMapping("/trend/{movieId}") public Result<List<TrendVO>> getTrend(@PathVariable Long movieId) { return Result.success(analysisService.getTrendByDate(movieId)); } /** * 按电影ID获取情感分布 */ @GetMapping("/sentiment/{movieId}") public Result<Map<String, Long>> getSentimentDistribution(@PathVariable Long movieId) { return Result.success(analysisService.getSentimentDistribution(movieId)); } }

5.3 SQL 统计实现

AnalysisServiceImpl中,核心的统计 SQL 如下:

-- 查询某电影的情感分布 SELECT a.sentiment_label AS label, COUNT(*) AS count FROM t_comment c INNER JOIN t_sentiment_analysis a ON c.id = a.comment_id WHERE c.movie_id = #{movieId} GROUP BY a.sentiment_label;
-- 查询某电影的每日评论趋势 SELECT DATE_FORMAT(c.comment_date, '%Y-%m-%d') AS date, COUNT(*) AS count FROM t_comment c WHERE c.movie_id = #{movieId} GROUP BY DATE_FORMAT(c.comment_date, '%Y-%m-%d') ORDER BY date;
-- 查询负面评论明细(Top N) SELECT c.user_name, c.content, c.comment_date, a.sentiment_score FROM t_comment c INNER JOIN t_sentiment_analysis a ON c.id = a.comment_id WHERE c.movie_id = #{movieId} AND a.sentiment_label = 'negative' ORDER BY a.sentiment_score ASC LIMIT #{limit};

这里的统计 SQL 在 MyBatis Mapper 中通过@Select注解或 XML 文件实现。

5.4 SpringBoot + MyBatis 配置

application.yml中的数据库配置:

spring: datasource: url: jdbc:mysql://localhost:3306/movie_analysis?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your-password driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 database: 0 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.movieanalysis.entity configuration: map-underscore-to-camel-case: true

注意:如果你的 MySQL 是 5.x 版本,数据库驱动用com.mysql.cj.jdbc.Driver没问题;如果遇到时区问题,可以去掉serverTimezone参数或改为Asia/Shanghai

6. 前端数据可视化实现

6.1 前端技术选型

前端推荐采用 Vue + Element UI + ECharts 的组合:

  • Vue:负责页面交互和数据绑定。
  • Element UI:提供表格、表单、菜单等基础组件。
  • ECharts:实现词云、折线图、饼图、柱状图等可视化图表。

6.2 舆情看板页面实现

以“影视舆情总览看板”为例,页面布局为:

  • 顶部:电影选择下拉框、整体统计卡片(总评论数、正面占比、负面占比、平均情感分)。
  • 中间左侧:情感分布饼图。
  • 中间右侧:评论数趋势折线图。
  • 底部左侧:评论高频词词云。
  • 底部右侧:负面评论 Top 列表。

核心代码示例(Vue 组件):

// 文件路径:src/views/Dashboard.vue(核心片段) <template> <div class="dashboard"> <!-- 统计卡片 --> <el-row :gutter="20"> <el-col :span="6"> <el-card shadow="hover"> <div class="stat-item"> <div class="stat-label">总评论数</div> <div class="stat-value">{{ overview.totalComments }}</div> </div> </el-card> </el-col> <el-col :span="6"> <el-card shadow="hover"> <div class="stat-item"> <div class="stat-label">正面评论占比</div> <div class="stat-value">{{ overview.positiveRate }}%</div> </div> </el-card> </el-col> <el-col :span="6"> <el-card shadow="hover"> <div class="stat-item"> <div class="stat-label">负面评论占比</div> <div class="stat-value">{{ overview.negativeRate }}%</div> </div> </el-card> </el-col> <el-col :span="6"> <el-card shadow="hover"> <div class="stat-item"> <div class="stat-label">平均情感分</div> <div class="stat-value">{{ overview.avgScore }}</div> </div> </el-card> </el-col> </el-row> <!-- 图表区域 --> <el-row :gutter="20" style="margin-top: 20px;"> <el-col :span="12"> <el-card shadow="hover" title="情感分布"> <div ref="sentimentChart" style="height: 350px;"></div> </el-card> </el-col> <el-col :span="12"> <el-card shadow="hover" title="评论趋势"> <div ref="trendChart" style="height: 350px;"></div> </el-card> </el-col> </el-row> </div> </template> <script> import * as echarts from 'echarts'; export default { name: 'Dashboard', data() { return { movieId: null, overview: { totalComments: 0, positiveRate: 0, negativeRate: 0, avgScore: 0 } }; }, methods: { async loadData(movieId) { // 1. 加载总览数据 const { data: overview } = await axios.get(`/api/analysis/overview/${movieId}`); this.overview = overview; // 2. 加载并渲染情感分布饼图 const { data: sentimentData } = await axios.get(`/api/analysis/sentiment/${movieId}`); this.renderSentimentChart(sentimentData); // 3. 加载并渲染趋势折线图 const { data: trendData } = await axios.get(`/api/analysis/trend/${movieId}`); this.renderTrendChart(trendData); }, renderSentimentChart(data) { const chart = echarts.init(this.$refs.sentimentChart); chart.setOption({ tooltip: { trigger: 'item' }, series: [{ type: 'pie', radius: ['40%', '70%'], data: [ { value: data.positive, name: '正面' }, { value: data.neutral, name: '中性' }, { value: data.negative, name: '负面' } ], label: { formatter: '{b}: {d}%' } }] }); }, renderTrendChart(data) { const chart = echarts.init(this.$refs.trendChart); chart.setOption({ xAxis: { type: 'category', data: data.dates }, yAxis: { type: 'value' }, series: [{ type: 'line', smooth: true, data: data.counts, areaStyle: { opacity: 0.3 } }], tooltip: { trigger: 'axis' } }); } } }; </script>

6.3 词云图实现

词云图是舆情项目的亮点模块。ECharts 官方的词云图示例在 5.x 版本后变成了echarts-wordcloud扩展包,需要单独安装:

npm install echarts echarts-wordcloud

核心配置如下:

import 'echarts-wordcloud'; const chart = echarts.init(this.$refs.wordCloudChart); chart.setOption({ series: [{ type: 'wordCloud', shape: 'circle', left: 'center', top: 'center', width: '90%', height: '90%', sizeRange: [14, 60], rotationRange: [0, 0], drawOutOfBound: false, data: this.wordCloudData // 格式: [{ name: '演技', value: 132 }, ...] }] });

词云数据从后端接口获取,接口内部使用 AI 模型或分词工具(如 HanLP、Jieba)对评论进行关键词抽取,按词频统计后返回。

7. 系统安全与用户认证

7.1 登录认证实现

毕设项目通常不需要复杂的微服务安全框架,使用 JWT + Spring Security 或简单拦截器即可。这里推荐使用 Spring Security + JWT 组合,既展示技术深度,答辩时也有内容可讲。

核心依赖:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>

注意:如果使用 Spring Boot 3.x,jjwt 0.9.1可能不兼容 JDK 17 的 JAXB 模块,需要额外引入javax.xml.bind:jaxb-api,或换用io.jsonwebtoken:jjwt:0.12.x版本。

JWT 工具类核心代码:

// 文件路径:src/main/java/com/example/movieanalysis/common/JwtUtils.java @Component public class JwtUtils { @Value("${jwt.secret}") private String secret; @Value("${jwt.expire-hours}") private Long expireHours; /** * 生成Token */ public String generateToken(String username, String role) { return Jwts.builder() .setSubject(username) .claim("role", role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + expireHours * 3600_000L)) .signWith(SignatureAlgorithm.HS256, secret) .compact(); } /** * 解析Token,获取用户名 */ public String parseToken(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody() .getSubject(); } }

7.2 安全边界提醒

作为毕设项目,这里必须提醒几个安全底线:

  • 密码存储:使用 BCrypt 加密,不要用 MD5 存密码。
  • API Key 保护:大模型的 API Key 绝不能放在前端代码中,必须存储在后端配置。
  • SQL 注入:使用 MyBatis 的#{}参数绑定,不要用${}拼接 SQL。
  • 接口权限:涉及管理操作的接口必须做登录校验。

8. 项目运行与部署实战

8.1 本地快速启动步骤

下面是从零到运行的最简流程:

# 1. 创建数据库并导入脚本 mysql -uroot -p source /path/to/sql/init.sql; # 2. 启动 Redis(如果使用缓存) redis-server /path/to/redis.conf # 3. 修改后端 application.yml 配置数据库和AI接口 # 4. 启动后端 mvn spring-boot:run # 5. 启动前端 cd frontend npm install npm run serve

启动成功后访问:

  • 前端页面:http://localhost:8081
  • 后端接口:http://localhost:8080/api/...
  • Swagger 接口文档(如集成):http://localhost:8080/swagger-ui.html

8.2 前后端分离部署方案

如果你的毕设要求部署到服务器上展示,推荐两种方式:

方式一:前后端分开部署

  • 后端打包为 jar 包,使用java -jar movie-analysis.jar运行。
  • 前端npm run build生成 dist 静态文件,使用 Nginx 托管,并通过 Nginx 反向代理后端接口。

Nginx 配置示例:

server { listen 80; server_name your-server-ip; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }

方式二:Spring Boot 内置静态资源访问

将前端构建后的dist目录放到src/main/resources/static/下,重新打包后直接访问后端端口即可。这种方式适合毕设演示,但不推荐大型项目使用。

9. 常见问题与排查思路

以我自己的经验,这个项目最容易遇到以下问题:

问题现象常见原因解决思路
项目启动报错:Field userMapper was not injectedMapper 接口没有被扫描启动类添加@MapperScan("com.example.movieanalysis.mapper")
调用 AI 接口报 401 或 403API Key 错误或已过期检查application.yml中的api-key配置,查看服务商控制台确认额度
前端跨域请求失败后端未配置 CORS后端添加跨域配置类实现WebMvcConfigurer重写addCorsMappings
数据库中文乱码JDBC URL 未指定 UTF-8,或建库时未指定字符集URL 添加characterEncoding=utf8,建库语句指定DEFAULT CHARSET=utf8mb4
情感分析结果全部为 neutral大模型返回 JSON 格式解析失败,走了降级逻辑parseResponse方法打断点,查看模型返回的原始内容
Spring Boot 3.x 下 JWT 报错javax 包名已变更为 jakarta换用 Spring Boot 2.7.x 或调整 JWT 库版本
Redis 连接失败Redis 服务未启动或密码配置错误redis-cli ping检查连接,确认spring.redis.password配置

9.1 跨域配置示例

// 文件路径:src/main/java/com/example/movieanalysis/config/CorsConfig.java @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

9.2 AI 接口超时问题

默认的RestTemplate没有设置超时时间,生产环境会导致线程被无限阻塞。建议使用RestTemplate自定义配置:

@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); factory.setConnectTimeout(5000); factory.setReadTimeout(15000); return new RestTemplate(factory); } }

10. 最佳实践与工程建议

10.1 数据层面

  • 评论数据建议提前清洗:去重(同一条评论可能来自不同来源)、去 HTML 标签、过滤广告。
  • 大模型分析考虑设置批处理状态:0=待分析, 1=分析中, 2=已完成, 3=失败,失败任务支持重跑。
  • 定期清理过期缓存,避免 Redis 内存暴涨。

10.2 AI 成本控制

毕设项目经费有限,AI 接口调用需要注意:

  • 使用限定 token 长度的模型,对于短评,一次只传必要文本。
  • 设置温度 temperature=0,让输出尽量稳定。
  • 对同一电影的评论,在测试阶段只分析前 500 条,够展示即可。
  • 可在 Redis 中缓存每条评论的分析结果,避免重复消耗额度。

10.3 代码维护建议

  • 后端所有返回给前端的时间字段,建议统一格式为yyyy-MM-dd HH:mm:ss,避免前端时间格式化麻烦。
  • 大模型相关的提示词、API 配置全部抽取到配置项,不要写死在代码里。
  • 日志中打印 AI 调用耗时和请求参数,方便答辩时展示优化思路。

11. 答辩与项目展示技巧

这个项目在答辩时,建议从以下三个维度组织讲稿:

维度一:技术难点

  • AI 大模型如何与 SpringBoot 生态无缝集成。
  • 情感分析的准确率如何保障,模型返回内容格式不稳定时如何容错。
  • 数据库查询性能优化,比如评论表超过 10 万行后如何通过索引和分页保障响应。

维度二:业务闭环

  • 从原始评论数据到可视化看板,整个数据流转链路要讲清楚。
  • 突出“AI 不是噱头”,而是真正解决了传统词典分析解决不了的问题。

维度三:项目痛点

  • 大模型 API 调用为什么需要降级策略。
  • 情感分析结果为什么要独立于评论表存储。

12. 总结与后续扩展方向

本篇文章从零开始,围绕“SpringBoot + AI大模型影视评论舆情分析平台”这个毕设项目,完整拆解了系统架构、数据库设计、AI 情感分析实现、后端接口、前端可视化、部署流程和常见问题。核心内容可以简单概括为一条链路:评论文本 → 大模型情感分析 → 数据库存储 → API 接口 → ECharts 可视化

如果你已经把这个项目跑通,接下来可以考虑以下几个扩展方向:

  1. 加入定时任务:使用 Spring 的@Scheduled定时拉取最新评论并自动分析,实现舆情实时监控。
  2. 引入 ES 搜索引擎:评论数据量大幅增长后,使用 Elasticsearch 做全文检索和分析,聚合速度远高于 MySQL。
  3. 多模型对比:接入两个以上大模型,对同一批评论做情感分析一致性比对,这在高档毕设中是很大的加分项。
  4. 热度预警:根据负面评论的增长率设置预警阈值,当某部电影负面舆情激增时,系统自动告警。

最后,还是那句老话:毕设项目的核心不是堆砌多少新技术,而是把每一个技术点讲清楚、能落地、可演示。把本文中 AI 接入的降级策略、表结构设计、可视化看板做好,你已经可以平稳通过大多数学校的毕设答辩了。

如果这篇文章对你有帮助,欢迎收藏备用。如果你在搭建过程中遇到了本文没有覆盖到的问题,也可以在评论区描述你的错误日志和运行环境,我会尽力帮你分析排查。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 22:56:25

基于STM32的全自动节水灌溉系统:从传感器选型到状态机实现

简介&#xff1a;本资源是一套完整的基于STM32的全自动节水灌溉系统毕业设计实现方案&#xff0c;面向计算机、自动化、通信及人工智能等相关专业学生与教师&#xff0c;解决农业物联网场景下土壤湿度感知、智能启停灌溉、远程数据上报等核心问题&#xff0c;适用于课程设计、大…

作者头像 李华
网站建设 2026/9/1 22:55:23

技术面试中的“八股文”:从原理到实践的价值与应对策略

技术随笔&#xff1a;为什么面试爱问八股文最近团队在招人&#xff0c;我坐在面试官的位置上&#xff0c;面了十几位候选人。面完之后我自己也忍不住在想一个问题&#xff1a;为什么我们面试的时候&#xff0c;总是绕不开那些“八股文”式的问题&#xff1f;HashMap的原理、TCP…

作者头像 李华
网站建设 2026/9/1 22:54:17

前端面试高频100题知识地图:从事件循环到Vue响应式原理

前端面试八股文这两年几乎成了每个前端人的必经关卡。不管你是刚刷完基础准备投简历的应届生&#xff0c;还是工作两三年想跳槽的进阶开发&#xff0c;打开招聘软件先看到的永远是那几道高频题&#xff1a;事件循环输出顺序、闭包内存泄漏、浏览器缓存、Vue 响应式原理。这套东…

作者头像 李华
网站建设 2026/9/1 22:53:35

技术面试八股文真相:从背题到建知识树的高效备战指南

晚上十一点&#xff0c;我还在工位上改最后一个 commit。旁边实习生的屏幕上摊着一整页“Java面试必备八股文”&#xff0c;他抬头问我&#xff1a;哥&#xff0c;这玩意儿到底有没有用&#xff1f;我一时语塞。这个问题我自己也想了很久。“八股文”这三个字&#xff0c;在程序…

作者头像 李华
网站建设 2026/9/1 22:52:09

网约车平台小程序全栈实战:Vue3+Spring Boot 3架构解析与部署

简介&#xff1a;这是一套基于Vue3与Spring Boot3技术栈开发的网约车平台小程序完整源码&#xff0c;面向前端、后端及全栈开发者&#xff0c;适用于毕业设计、课程实训、企业原型快速搭建等场景&#xff0c;解决出行类应用前后端协同开发与高并发架构落地的实际问题。压缩包共…

作者头像 李华
网站建设 2026/9/1 22:48:35

AI时代比技能更值钱的能力:判断力、上下文与反馈闭环

这次我们看的不是模型权重&#xff0c;也不是一键部署包&#xff0c;而是一个内容产品&#xff1a;《【真人感中配】Notion 产品负责人&#xff1a;AI 时代&#xff0c;比技能更值钱的是什么&#xff1f;》。先把它拆开看&#xff1a;Notion 是现在 AI 产品团队用得最多的协作工…

作者头像 李华