1. 项目概述:SpringBoot+Vue课程答疑系统平台
这个基于SpringBoot+Vue的课程答疑系统,是专门为高校计算机专业学生设计的毕业设计级项目。它完整实现了在线课程问答、师生互动、知识管理的核心功能,采用前后端分离架构,可直接作为Java Web方向的毕业设计作品提交。我在实际开发中发现,这类系统能很好地展示学生对主流技术栈的掌握程度,特别是SpringBoot后端服务和Vue前端框架的整合能力。
系统采用经典的B/S架构,后端使用SpringBoot 2.7.x构建RESTful API,前端采用Vue 3组合式API开发,数据库选用MySQL 8.0。整套代码包含完整的权限控制模块,采用JWT进行身份认证,接口文档使用Swagger生成,完全符合现代Web开发规范。特别值得一提的是,项目中还实现了富文本编辑器和文件上传功能,这对课程答疑场景尤为重要。
2. 技术架构解析
2.1 后端技术栈设计
SpringBoot作为后端核心框架,我选择了2.7.15这个长期支持版本。这个选择基于三个考量:首先,2.7.x系列稳定性经过验证;其次,对Java 17的完整支持;最后,丰富的starter依赖可以快速集成各种功能模块。项目结构采用典型的三层架构:
code复制src/main/java
├── config # 配置类
├── controller # 控制层
├── service # 业务层
├── dao # 数据访问层
├── entity # 实体类
├── dto # 数据传输对象
└── util # 工具类
数据库设计方面,我特别注重了以下几个关键表的设计:
user表:采用BCrypt加密存储密码question表:包含问题状态流转字段answer表:建立与问题的外键关联course表:实现课程分类管理
2.2 前端技术方案
Vue 3的组合式API让前端开发更加灵活。项目使用Vite作为构建工具,相比传统Webpack能获得更快的开发体验。主要技术选型包括:
- Element Plus作为UI组件库
- Axios处理HTTP请求
- Vue Router管理路由
- Pinia进行状态管理
- ECharts实现数据可视化
前端工程结构设计如下:
code复制src/
├── api/ # 接口定义
├── assets/ # 静态资源
├── components/ # 公共组件
├── router/ # 路由配置
├── stores/ # 状态管理
├── utils/ # 工具函数
└── views/ # 页面组件
3. 核心功能实现细节
3.1 用户认证模块
采用JWT进行无状态认证,这是现代Web应用的标配方案。后端创建JwtUtil工具类处理token生成与验证:
java复制public class JwtUtil {
private static final String SECRET = "your-256-bit-secret";
private static final long EXPIRATION = 86400000L; // 24小时
public static String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(SignatureAlgorithm.HS256, SECRET)
.compact();
}
public static String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
前端在axios拦截器中统一处理token:
javascript复制// 请求拦截器
service.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config
})
// 响应拦截器
service.interceptors.response.use(
response => response.data,
error => {
if (error.response.status === 401) {
// 处理token过期
}
return Promise.reject(error)
}
)
3.2 答疑功能实现
问题发布采用富文本编辑器,我选择了WangEditor这个轻量级解决方案。后端处理HTML内容时需要特别注意XSS防护:
java复制@PostMapping("/questions")
public Result createQuestion(@RequestBody QuestionDTO dto) {
// 使用Jsoup进行XSS过滤
String safeContent = Jsoup.clean(dto.getContent(),
Whitelist.basicWithImages()
.addTags("div","span")
.addAttributes(":all", "style"));
Question question = new Question();
question.setContent(safeContent);
// 其他字段处理...
return Result.success(questionService.save(question));
}
前端编辑器集成关键代码:
vue复制<template>
<div id="editor-container"></div>
</template>
<script setup>
import { onMounted } from 'vue'
import WangEditor from 'wangeditor'
onMounted(() => {
const editor = new WangEditor('#editor-container')
editor.config.uploadImgShowBase64 = true // 图片base64处理
editor.create()
})
</script>
4. 数据库设计与优化
4.1 核心表结构
用户表设计示例:
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '登录账号',
`password` varchar(100) NOT NULL COMMENT '加密密码',
`real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`role` enum('student','teacher','admin') NOT NULL DEFAULT 'student',
`status` tinyint NOT NULL DEFAULT '1' COMMENT '0-禁用 1-正常',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
问题表设计特别注意了索引优化:
sql复制CREATE TABLE `question` (
`id` bigint NOT NULL AUTO_INCREMENT,
`title` varchar(200) NOT NULL,
`content` text NOT NULL,
`user_id` bigint NOT NULL,
`course_id` bigint NOT NULL,
`status` enum('pending','resolved','closed') NOT NULL DEFAULT 'pending',
`view_count` int DEFAULT '0',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_course_id` (`course_id`),
KEY `idx_status` (`status`),
FULLTEXT KEY `ft_title_content` (`title`,`content`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
4.2 查询性能优化
对于高频访问的问题列表接口,我采用了以下优化策略:
- 分页查询使用覆盖索引:
sql复制SELECT q.id, q.title, q.status, u.real_name, q.create_time
FROM question q
JOIN user u ON q.user_id = u.id
WHERE q.course_id = ?
ORDER BY q.create_time DESC
LIMIT ?, ?
- 使用Redis缓存热点问题:
java复制public List<QuestionVO> getHotQuestions(int limit) {
String cacheKey = "hot:questions:" + limit;
List<QuestionVO> cached = redisTemplate.opsForValue().get(cacheKey);
if (cached != null) {
return cached;
}
List<QuestionVO> list = questionMapper.selectHotQuestions(limit);
redisTemplate.opsForValue().set(cacheKey, list, 1, TimeUnit.HOURS);
return list;
}
5. 项目部署与运维
5.1 后端部署要点
SpringBoot应用打包为可执行JAR:
xml复制<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
生产环境推荐使用Docker部署:
dockerfile复制FROM openjdk:17-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
5.2 前端部署方案
Vue项目构建优化配置:
javascript复制// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
}
}
})
Nginx配置示例:
nginx复制server {
listen 80;
server_name yourdomain.com;
location / {
root /var/www/html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
}
}
6. 常见问题与解决方案
6.1 跨域问题处理
SpringBoot后端配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
开发环境也可以在Vite中配置代理:
javascript复制// vite.config.js
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
6.2 文件上传限制
SpringBoot默认文件上传限制为1MB,需要调整配置:
yaml复制spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
同时前端需要处理大文件分片上传:
javascript复制const chunkSize = 2 * 1024 * 1024 // 2MB
const chunks = Math.ceil(file.size / chunkSize)
for (let i = 0; i < chunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize)
const formData = new FormData()
formData.append('file', chunk)
formData.append('chunkNumber', i)
formData.append('totalChunks', chunks)
await uploadChunk(formData)
}
7. 毕设答辩准备建议
7.1 技术亮点展示
建议重点展示以下技术点:
- JWT认证流程的完整实现
- 前后端分离架构的设计思路
- 富文本编辑器的安全处理
- 数据库查询性能优化方案
- 项目的可扩展性设计
7.2 常见答辩问题准备
- 为什么选择SpringBoot+Vue这套技术栈?
- 系统如何处理高并发场景?
- 在安全性方面做了哪些考虑?
- 如果用户量增长10倍,系统需要如何扩展?
- 项目中有哪些可以继续优化的地方?
我在实际开发中遇到的一个典型问题是Vue组件间的状态共享。最初使用props层层传递非常繁琐,后来改用Pinia后代码简洁了许多。这让我深刻体会到状态管理库在复杂前端应用中的价值。
