1. 项目概述
这个毕业设计系统采用SpringBoot+Vue+MySQL技术栈构建,是一个典型的现代化前后端分离应用。我在实际开发过程中发现,这种架构组合特别适合高校毕业设计管理场景,既能满足教务管理的复杂业务需求,又能保证系统的响应速度和用户体验。
系统主要包含学生选题、导师指导、论文提交、成绩评定等核心功能模块。通过SpringBoot提供的RESTful API与Vue前端交互,MySQL则负责持久化存储所有业务数据。这种架构设计让系统具备了良好的扩展性和维护性,我在开发后期新增答辩管理模块时,只用了不到两天就完成了功能迭代。
2. 技术架构解析
2.1 后端SpringBoot实现
后端采用SpringBoot 2.7.x版本构建,这是我经过多个项目验证的稳定版本。在pom.xml中除了常规的spring-boot-starter-web依赖外,还特别引入了这些关键组件:
xml复制<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
数据库连接池选用Druid而非HikariCP,主要是考虑到毕业设计系统在答辩季会出现明显的访问高峰,Druid的监控和熔断功能更适合这种场景。在application.yml中我这样配置多数据源:
yaml复制spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/graduation?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3307/graduation?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
2.2 前端Vue框架选型
前端采用Vue 3 + Element Plus组合,通过axios与后端通信。项目初始化时我特别优化了vue.config.js的配置:
javascript复制module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
},
configureWebpack: {
performance: {
hints: false
},
optimization: {
splitChunks: {
minSize: 10000,
maxSize: 250000
}
}
}
}
这个配置解决了开发阶段最让人头疼的跨域问题,同时通过合理的代码分割控制打包体积。在实际部署时,建议开启gzip压缩,这能让主bundle文件从1.2MB减小到300KB左右。
3. 数据库设计与优化
3.1 核心表结构设计
MySQL数据库设计遵循第三范式,主要包含这些核心表:
sql复制CREATE TABLE `t_student` (
`id` int NOT NULL AUTO_INCREMENT,
`student_no` varchar(20) NOT NULL COMMENT '学号',
`name` varchar(50) NOT NULL,
`class_id` int NOT NULL,
`password` varchar(100) NOT NULL COMMENT '加密存储',
`phone` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_student_no` (`student_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `t_teacher` (
`id` int NOT NULL AUTO_INCREMENT,
`teacher_no` varchar(20) NOT NULL,
`name` varchar(50) NOT NULL,
`title` varchar(20) DEFAULT NULL COMMENT '职称',
`password` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_teacher_no` (`teacher_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 查询性能优化
在系统压力测试阶段,我发现论文提交记录表的联表查询性能较差。通过EXPLAIN分析后,添加了这些索引:
sql复制ALTER TABLE `t_paper` ADD INDEX `idx_student_status` (`student_id`, `status`);
ALTER TABLE `t_comment` ADD INDEX `idx_paper_teacher` (`paper_id`, `teacher_id`);
同时调整了InnoDB缓冲池大小:
sql复制SET GLOBAL innodb_buffer_pool_size = 2*1024*1024*1024;
这些优化让关键接口的响应时间从平均800ms降到了200ms以内。对于毕业设计系统这种读多写少的应用,合理的索引设计比硬件升级更有效。
4. 关键功能实现细节
4.1 论文查重接口实现
系统集成了第三方查重服务,我采用策略模式设计了这个功能:
java复制public interface SimilarityCheckStrategy {
CheckResult check(String content);
}
@Service
@RequiredArgsConstructor
public class SimilarityCheckService {
private final Map<String, SimilarityCheckStrategy> strategyMap;
public CheckResult check(String content, String provider) {
return strategyMap.get(provider + "Strategy").check(content);
}
}
这样后续新增查重供应商时,只需要实现新的Strategy即可,符合开闭原则。在并发处理上,我使用了Spring的@Async注解实现异步查重:
java复制@Async("taskExecutor")
public Future<CheckResult> asyncCheck(String content) {
// 查重逻辑
}
4.2 文件上传与预览
文件上传采用分块上传策略,前端使用vue-simple-uploader组件:
vue复制<uploader
:options="options"
:file-status-text="statusText"
@file-added="onFileAdded"
class="uploader-example">
<uploader-unsupport></uploader-unsupport>
<uploader-drop>
<p>拖拽文件到此处上传</p>
<uploader-btn>选择文件</uploader-btn>
</uploader-drop>
<uploader-list></uploader-list>
</uploader>
后端对应的分块合并逻辑:
java复制public String mergeChunks(String md5, String fileName) throws IOException {
String tempFolder = System.getProperty("java.io.tmpdir") + "/upload/" + md5;
File dir = new File(tempFolder);
File dest = new File(uploadPath + fileName);
try (FileOutputStream fos = new FileOutputStream(dest, true)) {
for (int i = 0; i < dir.listFiles().length; i++) {
File chunk = new File(tempFolder, i + ".part");
Files.copy(chunk.toPath(), fos);
}
}
FileUtils.deleteDirectory(dir);
return fileName;
}
5. 系统部署实践
5.1 后端部署要点
使用Docker部署SpringBoot应用时,我建议采用多阶段构建:
dockerfile复制FROM maven:3.8.6-jdk-11 AS build
COPY . /app
WORKDIR /app
RUN mvn clean package -DskipTests
FROM openjdk:11-jre-slim
COPY --from=build /app/target/graduation-*.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
这样生成的镜像只有200MB左右,比直接打包完整JDK的镜像小了近500MB。在k8s部署时,记得配置这些健康检查:
yaml复制livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
5.2 前端Nginx配置
生产环境Nginx配置需要注意这些关键参数:
nginx复制server {
listen 80;
server_name graduation.example.com;
gzip on;
gzip_types text/plain application/javascript application/x-javascript text/css;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache";
}
location /api {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
}
}
这个配置实现了前端路由的history模式支持,同时开启了gzip压缩。特别注意静态资源的缓存策略设置,避免更新后浏览器加载旧版本文件。
6. 开发中的经验总结
在开发评审模块时,我最初使用了WebSocket实现实时通知,但后来发现对服务器资源消耗太大。最终改用SSE(Server-Sent Events)方案:
java复制@GetMapping("/notifications")
public SseEmitter streamNotifications(@RequestParam Long userId) {
SseEmitter emitter = new SseEmitter(3600_000L);
notificationService.addEmitter(userId, emitter);
emitter.onCompletion(() -> notificationService.removeEmitter(userId, emitter));
return emitter;
}
这种方案在保持实时性的同时,服务端压力减轻了约60%。另一个值得分享的经验是使用Hutool工具库处理Excel导出:
java复制public void exportStudents(HttpServletResponse response) {
List<Student> list = studentService.list();
ExcelWriter writer = ExcelUtil.getWriter(true);
writer.addHeaderAlias("name", "姓名");
writer.write(list, true);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
writer.flush(response.getOutputStream());
writer.close();
}
相比传统的POI方式,代码量减少了70%且性能更好。这些实战经验都是在文档中很难找到的宝贵技巧。
