1. 项目概述与核心价值
作为一个养宠多年的技术从业者,我深知宠物主人们对于交流养宠经验、分享萌宠日常的强烈需求。这个基于SpringBoot的家庭养宠社交平台,正是为了解决这个痛点而设计的毕业设计项目。它不仅是一个典型的企业级Java Web应用开发案例,更是一个具有实际应用价值的社交产品原型。
系统采用了当前主流的SpringBoot+MyBatis技术栈,前端使用Thymeleaf模板引擎,数据库选用MySQL。整个项目实现了用户管理、宠物档案、动态分享、社区互动等核心功能模块。特别值得一提的是,我在开发过程中针对宠物社交场景做了许多细节优化,比如宠物健康记录提醒、附近宠友推荐等实用功能。
2. 系统架构设计解析
2.1 技术选型考量
选择SpringBoot作为基础框架主要基于以下几个实际考量:
- 快速启动:内嵌Tomcat,无需复杂配置即可运行
- 约定优于配置:减少了大量XML配置工作
- 丰富的Starter:轻松集成MyBatis、Redis等组件
- 健康检查:自带Actuator模块方便监控
数据库方面,MySQL 5.7版本提供了良好的JSON支持,这对存储宠物的多样化特征数据特别有用。前端选用Bootstrap+Thymeleaf组合,既保证了响应式布局,又能与后端无缝集成。
2.2 系统分层架构
系统采用经典的三层架构:
code复制表现层:Thymeleaf模板 + Controller
业务层:Service + 自定义业务异常
数据层:MyBatis + MySQL + Redis缓存
我在架构设计中特别加入了几个关键点:
- 统一的异常处理机制(@ControllerAdvice)
- 参数校验框架(Hibernate Validator)
- 接口幂等性设计(防重复提交)
- 敏感数据脱敏处理
3. 核心功能模块实现
3.1 用户系统设计
用户模块采用了RBAC权限模型,主要包含以下关键表设计:
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '登录账号',
`password` varchar(100) NOT NULL COMMENT '加密密码',
`nickname` varchar(50) DEFAULT NULL COMMENT '显示昵称',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
`pet_type` varchar(20) DEFAULT NULL COMMENT '主要宠物类型',
`status` tinyint DEFAULT '1' COMMENT '状态(0禁用1正常)',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
密码存储采用BCrypt加密算法,这是目前最安全的密码哈希方案之一:
java复制@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
3.2 宠物档案管理
宠物档案是系统的核心数据,我设计了扩展性很强的数据结构:
java复制public class PetProfile {
private Long id;
private Long userId;
private String petName;
private Integer petType; // 1-猫 2-狗 3-其他
private String breed; // 品种
private Date birthday;
private Integer gender; // 0-未知 1-公 2-母
private String avatarUrl;
private String medicalHistory; // JSON格式存储医疗记录
private List<PetVaccine> vaccineRecords;
}
医疗记录采用JSON格式存储,便于扩展各种自定义字段。疫苗记录则使用关联表实现:
sql复制CREATE TABLE `pet_vaccine` (
`id` bigint NOT NULL AUTO_INCREMENT,
`pet_id` bigint NOT NULL,
`vaccine_type` varchar(50) NOT NULL,
`vaccine_date` date NOT NULL,
`next_due_date` date DEFAULT NULL,
`hospital` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_pet_id` (`pet_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.3 社区动态功能
动态发布采用了类似微博的设计模式,支持文字、图片和视频:
java复制public class PetMoment {
private Long id;
private Long userId;
private Long petId;
private String content;
private MomentType type; // TEXT, IMAGE, VIDEO
private List<String> mediaUrls;
private Integer likeCount;
private Integer commentCount;
private Date createTime;
}
为了提高动态列表的查询性能,我做了以下优化:
- 使用Redis缓存热门动态
- 对大文本内容进行压缩存储
- 实现分库分表策略(按用户ID哈希)
- 建立复合索引(user_id + create_time)
4. 特色功能实现细节
4.1 宠物健康提醒
基于Quartz实现了定时提醒功能:
java复制public class HealthReminderJob implements Job {
@Override
public void execute(JobExecutionContext context) {
// 查询未来3天需要疫苗的宠物
List<VaccineReminder> reminders = vaccineMapper.selectUpcomingVaccines(3);
reminders.forEach(reminder -> {
String message = String.format("%s的%s疫苗即将到期(%s)",
reminder.getPetName(),
reminder.getVaccineType(),
reminder.getDueDate());
notificationService.send(reminder.getUserId(), message);
});
}
}
4.2 附近宠友推荐
基于Redis GEO实现附近用户搜索:
java复制public List<NearbyUser> findNearbyUsers(Double longitude, Double latitude, Double radius) {
String key = "user:geo";
// 添加用户位置
redisTemplate.opsForGeo().add(key,
new Point(longitude, latitude),
userId.toString());
// 查询半径内的用户
Circle within = new Circle(new Point(longitude, latitude),
new Distance(radius, Metrics.KILOMETERS));
GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo()
.radius(key, within);
// 处理结果...
}
5. 开发中的难点与解决方案
5.1 图片存储优化
初期使用本地存储遇到的几个问题:
- 图片加载慢
- 存储空间不足
- 备份困难
最终解决方案:
- 采用七牛云对象存储
- 实现图片压缩(Thumbnailator)
- 增加CDN加速
- 设计图片清理策略(30天未访问的图片归档)
核心代码示例:
java复制public String uploadImage(MultipartFile file) {
// 生成唯一文件名
String fileName = UUID.randomUUID() + getFileExtension(file);
// 压缩图片
BufferedImage thumbnail = Thumbnails.of(file.getInputStream())
.size(800, 800)
.asBufferedImage();
// 上传到云存储
qiniuService.upload(thumbnail, fileName);
return cdnDomain + fileName;
}
5.2 高并发点赞处理
直接操作数据库的方案在压测时出现性能瓶颈,优化方案:
- 使用Redis计数器
- 异步持久化到数据库
- 实现分布式锁防重复点击
优化后的点赞流程:
java复制public void likeMoment(Long momentId, Long userId) {
String lockKey = "moment:like:" + momentId;
String countKey = "moment:like:count:" + momentId;
String userKey = "moment:like:users:" + momentId;
// 获取分布式锁
boolean locked = redisLock.tryLock(lockKey, 3, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("操作太频繁");
}
try {
// 检查是否已点赞
if (redisTemplate.opsForSet().isMember(userKey, userId.toString())) {
return;
}
// 记录用户并增加计数
redisTemplate.opsForSet().add(userKey, userId.toString());
redisTemplate.opsForValue().increment(countKey);
// 异步保存到数据库
asyncTask.saveLikeToDB(momentId, userId);
} finally {
redisLock.unlock(lockKey);
}
}
6. 部署与性能优化
6.1 生产环境部署方案
采用Docker Compose部署方案:
yaml复制version: '3'
services:
app:
image: pet-social:1.0
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- mysql
- redis
mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=pet_social
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
mysql_data:
redis_data:
6.2 性能调优实践
通过JMeter压测发现的几个性能瓶颈及解决方案:
- N+1查询问题:
- 现象:获取动态列表时频繁查询用户信息
- 方案:使用MyBatis的
标签实现一对多查询
- 缓存穿透:
- 现象:频繁查询不存在的动态ID
- 方案:使用布隆过滤器预先过滤无效ID
- 大文件上传:
- 现象:上传视频时内存溢出
- 方案:配置Multipart最大大小并实现分片上传
properties复制# application.properties
spring.servlet.multipart.max-file-size=50MB
spring.servlet.multipart.max-request-size=50MB
7. 项目扩展方向
在实际开发过程中,我发现这个系统还有很大的扩展空间:
- 宠物智能硬件对接:
- 接入智能喂食器、摄像头等IoT设备
- 实现宠物活动数据可视化
- 宠物医疗服务整合:
- 对接在线问诊平台
- 实现疫苗本电子化
- 进阶社交功能:
- 宠物相亲匹配算法
- 线下聚会活动组织
- 商业化可能性:
- 宠物用品电商模块
- 宠物保险推荐系统
这个项目虽然作为毕业设计,但完全具备商业化的潜力。我在开发过程中特别注重了系统的扩展性设计,所有核心表都预留了足够的扩展字段,服务层也采用了面向接口编程,方便后续功能扩展。