1. 项目概述与背景
在当今社交网络泛滥的时代,我们常常面临一个尴尬的困境:大型社交平台功能繁杂却缺乏针对性,而小众社交应用又往往功能单一。作为一名长期关注社交产品开发的程序员,我发现校园和兴趣社群这类垂直场景特别需要一个轻量级但功能完备的解决方案。这就是为什么我会选择基于SSM框架开发这个交友信息管理系统作为毕业设计项目。
这个系统的核心定位是解决三个实际问题:第一,如何为特定群体(如大学生)提供安全可靠的社交环境;第二,如何设计高效的信息匹配机制而不引入过度复杂的算法;第三,如何在有限服务器资源下保证系统响应速度。经过三个月的开发和调优,最终实现的系统在校园测试环境中支持了200+用户的同时在线使用,信息匹配准确率达到78%,页面平均响应时间控制在1.2秒以内。
2. 技术选型与架构设计
2.1 为什么选择SSM框架组合
在技术选型阶段,我对比了Spring Boot、Play Framework等多种Java Web框架,最终坚持选择传统的SSM组合主要基于以下考量:
- 教学价值:作为毕业设计,SSM能更全面地展示MVC分层思想
- 控制粒度:Spring的IoC容器可以精确控制每个Bean的依赖关系
- ORM平衡:MyBatis在SQL可控性和开发效率间取得了良好平衡
系统采用经典的三层架构:
code复制表示层(SpringMVC)
↓
业务层(Spring)
↓
持久层(MyBatis)
2.2 数据库设计要点
用户表(user)设计时特别注意了垂直分表:
sql复制CREATE TABLE `user_basic` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(20) UNIQUE NOT NULL,
`password` CHAR(60) NOT NULL -- BCrypt加密
);
CREATE TABLE `user_profile` (
`user_id` BIGINT PRIMARY KEY,
`gender` ENUM('M','F','O'),
`birth_date` DATE,
`tags` JSON -- 存储兴趣标签
);
这种设计带来了三个优势:
- 敏感信息隔离存储
- 减少不必要字段的查询
- JSON类型直接支持标签检索
3. 核心功能实现细节
3.1 会员安全模块
密码加密没有采用常见的MD5而是选择BCrypt:
java复制@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // 强度因子12
}
在权限控制上,我实现了动态RBAC模型:
java复制@PreAuthorize("hasPermission(#userId, 'PROFILE_EDIT')")
public void updateProfile(Long userId, ProfileDTO dto) {
// 业务逻辑
}
踩坑记录:初期使用拦截器实现权限控制,后来发现Spring Security更优雅地支持方法级权限注解,重构后代码量减少了40%
3.2 交友信息匹配算法
考虑到毕业设计的时间成本,我设计了一种基于Jaccard相似度的轻量级匹配算法:
java复制public List<MatchResult> matchUsers(Long userId) {
User target = userDao.selectById(userId);
return userDao.selectPotentialMatches()
.stream()
.filter(u -> !u.getId().equals(userId))
.map(u -> new MatchResult(u, calculateSimilarity(target, u)))
.sorted(comparingDouble(MatchResult::getScore).reversed())
.limit(20)
.collect(Collectors.toList());
}
private double calculateSimilarity(User a, User b) {
Set<String> tagsA = new HashSet<>(a.getTags());
Set<String> tagsB = new HashSet<>(b.getTags());
return (double) intersection(tagsA, tagsB).size() /
union(tagsA, tagsB).size();
}
3.3 高并发优化方案
针对图片加载的性能瓶颈,我采用了三级缓存策略:
- 浏览器缓存:设置Cache-Control头
- Redis缓存:热门图片Base64编码
- 本地磁盘缓存:Nginx静态资源服务
配置示例:
nginx复制server {
location ~* \.(jpg|png)$ {
expires 7d;
add_header Cache-Control "public";
}
}
4. 开发过程中的关键挑战
4.1 跨域会话保持问题
在前后端分离架构下,遇到了Cookie跨域失效的问题。最终解决方案是:
- 前端Axios配置:
javascript复制axios.defaults.withCredentials = true
- 后端CORS配置:
java复制@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowCredentials(true);
}
};
}
4.2 图片存储方案选型
对比了三种方案后选择了本地存储+CDN的方案:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 数据库BLOB | 管理简单 | 性能差 | 小文件 |
| 云存储 | 扩展性好 | 成本高 | 商业项目 |
| 本地存储 | 零成本 | 需备份 | 学生项目 |
实现代码:
java复制public String uploadImage(MultipartFile file) {
String filename = UUID.randomUUID() + getFileExtension(file);
Path path = Paths.get(uploadDir, filename);
Files.copy(file.getInputStream(), path, REPLACE_EXISTING);
return cdnDomain + "/uploads/" + filename;
}
5. 项目部署与测试
5.1 压力测试结果
使用JMeter模拟100并发用户:
| 接口 | 平均响应时间 | 错误率 | TPS |
|---|---|---|---|
| 登录 | 320ms | 0% | 285 |
| 信息列表 | 580ms | 0% | 167 |
| 图片加载 | 210ms | 0% | 476 |
5.2 安全测试要点
- 使用OWASP ZAP进行漏洞扫描
- 关键测试用例:
- SQL注入尝试
- XSS攻击测试
- CSRF令牌验证
- 修复方案:
- MyBatis全部使用#{}参数绑定
- 前端DOMPurify过滤
- 添加CSRF Token
6. 项目总结与改进方向
这个项目让我深刻体会到,一个看似简单的社交系统背后需要考虑的细节如此之多。有几个特别值得分享的经验:
-
过早优化是万恶之源:初期花费两周优化匹配算法,后来发现80%的用户只使用基础筛选功能
-
文档即代码:Swagger文档应该与接口开发同步进行,后期补充极其痛苦
-
测试要分层:从单元测试->集成测试->压力测试缺一不可
未来如果继续迭代,我会优先考虑三个方向的改进:
- 引入Elasticsearch提升搜索体验
- 增加WebSocket实时通知
- 开发移动端适配方案
这个项目的完整源码和数据库设计已经整理在GitHub仓库中,包含详细的部署文档和API说明。对于正在做类似毕业设计的同学,我的建议是:先确保核心流程跑通,再考虑锦上添花的功能,时间管理比技术炫技更重要。