一、个人简介
💖💖作者:计算机编程果茶熊
💙💙个人简介:曾长期从事计算机专业培训教学,担任过编程老师,同时本人也热爱上课教学,擅长Java、微信小程序、Python、Golang、安卓Android等多个IT方向。会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。平常喜欢分享一些自己开发中遇到的问题的解决办法,也喜欢交流技术,大家有技术代码这一块的问题可以问我!
💛💛想说的话:感谢大家的关注与支持!
💕💕文末获取源码联系计算机编程果茶熊
二、系统介绍
开发语言:Java+Python
数据库:MySQL
系统架构:B/S
后端框架:SpringBoot(Spring+SpringMVC+Mybatis)+Django
前端:Vue+HTML+CSS+JavaScript+jQuery
本音乐推荐系统是一款基于B/S架构的全栈应用,采用Java/Python双语言支持,分别基于Spring Boot(Spring+SpringMVC+Mybatis)和Django框架开发。
前端使用Vue+ElementUI+HTML技术栈,数据存储依托MySQL数据库。系统核心功能包括用户管理模块实现账号注册、登录及权限控制;音乐分类管理模块对歌曲进行多维度分类与标签管理;音乐信息管理模块支持歌曲元数据的增删改查;歌曲数据管理模块处理音频文件与播放数据;系统管理模块提供后台配置与运维功能;我的信息模块展示个人资料与听歌历史;最具特色的协同过滤推送功能则通过分析用户历史行为与偏好,实现个性化音乐推荐,帮助用户发现符合自身口味的新歌曲,大幅提升用户体验。整个系统架构清晰,前后端分离,接口规范,既满足普通用户的音乐发现需求,也为管理员提供了完善的内容管理功能,是一个功能完备的现代音乐推荐平台。
三、基于协同过滤算法的音乐推荐系统-视频解说
基于Spring Boot+Vue+协同过滤算法的音乐推荐系统设计与实现详解|计算机毕业设计选题
四、基于协同过滤算法的音乐推荐系统-功能展示
前台主页
前台音乐推荐
前台音乐信息
前台音乐信息详情
前台个人中心
后台可视化
后台歌曲数据管理
五、基于协同过滤算法的音乐推荐系统-代码展示
```
// 核心功能1: 协同过滤推荐功能
public List<MusicDTO> recommendMusicByCollaborativeFiltering(Long userId) {
// 获取当前用户的听歌历史
List<UserMusicHistory> userHistory = userMusicHistoryMapper.findByUserId(userId);
if (userHistory.isEmpty()) {
return recommendPopularMusic(10); // 冷启动处理
}
// 提取用户评分数据
Map<Long, Double> userRatings = new HashMap<>();
for (UserMusicHistory history : userHistory) {
userRatings.put(history.getMusicId(), calculateRating(history));
}
// 查找相似用户
List<UserSimilarity> similarUsers = new ArrayList<>();
List<User> allUsers = userMapper.findAll();
for (User otherUser : allUsers) {
if (otherUser.getId().equals(userId)) continue;
List<UserMusicHistory> otherUserHistory = userMusicHistoryMapper.findByUserId(otherUser.getId());
Map<Long, Double> otherUserRatings = new HashMap<>();
for (UserMusicHistory history : otherUserHistory) {
otherUserRatings.put(history.getMusicId(), calculateRating(history));
}
double similarity = calculatePearsonCorrelation(userRatings, otherUserRatings);
if (similarity > 0.3) { // 相似度阈值
similarUsers.add(new UserSimilarity(otherUser.getId(), similarity));
}
}
// 根据相似度排序
similarUsers.sort((a, b) -> Double.compare(b.getSimilarity(), a.getSimilarity()));
// 获取推荐音乐
Set<Long> recommendedMusicIds = new HashSet<>();
Map<Long, Double> musicScores = new HashMap<>();
for (UserSimilarity similarUser : similarUsers) {
List<UserMusicHistory> similarUserHistory = userMusicHistoryMapper.findByUserId(similarUser.getUserId());
for (UserMusicHistory history : similarUserHistory) {
if (!userRatings.containsKey(history.getMusicId())) {
double score = calculateRating(history) * similarUser.getSimilarity();
musicScores.merge(history.getMusicId(), score, Double::sum);
recommendedMusicIds.add(history.getMusicId());
}
}
}
// 转换为有序列表
List<MusicScore> rankedMusic = new ArrayList<>();
for (Long musicId : recommendedMusicIds) {
rankedMusic.add(new MusicScore(musicId, musicScores.getOrDefault(musicId, 0.0)));
}
rankedMusic.sort((a, b) -> Double.compare(b.getScore(), a.getScore()));
// 获取前10首推荐歌曲详情
List<MusicDTO> result = new ArrayList<>();
int count = 0;
for (MusicScore musicScore : rankedMusic) {
if (count >= 10) break;
Music music = musicMapper.findById(musicScore.getMusicId());
if (music != null) {
result.add(convertToDTO(music));
count++;
}
}
return result;
}
// 核心功能2: 音乐信息管理
@Transactional
public ApiResult updateMusicInfo(MusicUpdateRequest request) {
// 参数校验
if (request.getMusicId() == null || StringUtils.isEmpty(request.getTitle())) {
return ApiResult.fail("音乐ID和标题不能为空");
}
// 查询音乐是否存在
Music existingMusic = musicMapper.findById(request.getMusicId());
if (existingMusic == null) {
return ApiResult.fail("音乐不存在");
}
// 检查是否有权限修改
User currentUser = userService.getCurrentUser();
if (!currentUser.isAdmin() && !existingMusic.getUploaderId().equals(currentUser.getId())) {
return ApiResult.fail("无权修改该音乐信息");
}
// 更新基本信息
existingMusic.setTitle(request.getTitle());
existingMusic.setArtist(request.getArtist());
existingMusic.setAlbum(request.getAlbum());
existingMusic.setReleaseYear(request.getReleaseYear());
existingMusic.setDuration(request.getDuration());
existingMusic.setDescription(request.getDescription());
existingMusic.setUpdateTime(new Date());
existingMusic.setUpdateBy(currentUser.getId());
// 处理音乐封面
if (request.getCoverFile() != null && !request.getCoverFile().isEmpty()) {
try {
// 删除旧封面
if (StringUtils.isNotEmpty(existingMusic.getCoverUrl())) {
fileStorageService.deleteFile(existingMusic.getCoverUrl());
}
// 上传新封面
String coverUrl = fileStorageService.storeImage(
request.getCoverFile(),
"music/covers",
request.getMusicId() + "_" + System.currentTimeMillis()
);
existingMusic.setCoverUrl(coverUrl);
// 生成缩略图
String thumbnailUrl = imageProcessService.generateThumbnail(coverUrl, 200, 200);
existingMusic.setThumbnailUrl(thumbnailUrl);
} catch (IOException e) {
log.error("处理音乐封面失败", e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return ApiResult.fail("上传封面失败: " + e.getMessage());
}
}
// 更新音频文件
if (request.getAudioFile() != null && !request.getAudioFile().isEmpty()) {
try {
// 验证文件格式
String contentType = request.getAudioFile().getContentType();
if (contentType == null || !contentType.startsWith("audio/")) {
return ApiResult.fail("不支持的音频格式");
}
// 删除旧文件
if (StringUtils.isNotEmpty(existingMusic.getFileUrl())) {
fileStorageService.deleteFile(existingMusic.getFileUrl());
}
// 上传新文件
String fileUrl = fileStorageService.storeAudio(
request.getAudioFile(),
"music/files",
request.getMusicId() + "_" + System.currentTimeMillis()
);
existingMusic.setFileUrl(fileUrl);
existingMusic.setFileSize(request.getAudioFile().getSize());
existingMusic.setFileType(contentType);
// 更新音频时长
Integer duration = audioProcessService.extractDuration(fileUrl);
if (duration != null) {
existingMusic.setDuration(duration);
}
} catch (IOException e) {
log.error("处理音频文件失败", e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return ApiResult.fail("上传音频失败: " + e.getMessage());
}
}
// 更新分类信息
if (request.getCategoryIds() != null && !request.getCategoryIds().isEmpty()) {
// 删除旧分类关联
musicCategoryMapper.deleteByMusicId(request.getMusicId());
// 添加新分类关联
for (Long categoryId : request.getCategoryIds()) {
MusicCategory musicCategory = new MusicCategory();
musicCategory.setMusicId(request.getMusicId());
musicCategory.setCategoryId(categoryId);
musicCategory.setCreateTime(new Date());
musicCategoryMapper.insert(musicCategory);
}
}
// 更新标签信息
if (request.getTags() != null && !request.getTags().isEmpty()) {
// 删除旧标签
musicTagMapper.deleteByMusicId(request.getMusicId());
// 添加新标签
for (String tagName : request.getTags()) {
// 查找或创建标签
Tag tag = tagMapper.findByName(tagName);
if (tag == null) {
tag = new Tag();
tag.setName(tagName);
tag.setCreateTime(new Date());
tagMapper.insert(tag);
}
// 关联音乐和标签
MusicTag musicTag = new MusicTag();
musicTag.setMusicId(request.getMusicId());
musicTag.setTagId(tag.getId());
musicTag.setCreateTime(new Date());
musicTagMapper.insert(musicTag);
}
}
// 保存更新
musicMapper.update(existingMusic);
// 更新搜索索引
searchIndexService.updateMusicIndex(existingMusic);
return ApiResult.success("音乐信息更新成功");
}
// 核心功能3: 用户管理
@Transactional
public ApiResult registerUser(UserRegisterRequest request) {
// 参数校验
if (StringUtils.isEmpty(request.getUsername()) || StringUtils.isEmpty(request.getPassword())) {
return ApiResult.fail("用户名和密码不能为空");
}
// 用户名规则校验
if (!request.getUsername().matches("^[a-zA-Z0-9_]{4,20}$")) {
return ApiResult.fail("用户名只能包含字母、数字和下划线,长度4-20位");
}
// 密码强度校验
if (!passwordValidator.isStrong(request.getPassword())) {
return ApiResult.fail("密码必须包含大小写字母、数字和特殊字符,长度8-20位");
}
// 检查用户名是否已存在
if (userMapper.findByUsername(request.getUsername()) != null) {
return ApiResult.fail("用户名已被注册");
}
// 检查邮箱是否已存在
if (StringUtils.isNotEmpty(request.getEmail()) && userMapper.findByEmail(request.getEmail()) != null) {
return ApiResult.fail("邮箱已被注册");
}
// 检查手机号是否已存在
if (StringUtils.isNotEmpty(request.getPhone()) && userMapper.findByPhone(request.getPhone()) != null) {
return ApiResult.fail("手机号已被注册");
}
// 创建用户对象
User user = new User();
user.setUsername(request.getUsername());
user.setNickname(StringUtils.isNotEmpty(request.getNickname()) ? request.getNickname() : request.getUsername());
user.setEmail(request.getEmail());
user.setPhone(request.getPhone());
user.setGender(request.getGender());
user.setBirthday(request.getBirthday());
// 密码加密
String salt = generateSalt();
String encryptedPassword = passwordEncoder.encode(request.getPassword() + salt);
user.setPassword(encryptedPassword);
user.setSalt(salt);
// 设置默认头像
user.setAvatar("/static/images/default-avatar.png");
// 设置用户状态和角色
user.setStatus(UserStatus.NORMAL.getCode());
user.setRole(UserRole.USER.getCode());
// 设置注册信息
Date now = new Date();
user.setCreateTime(now);
user.setLastLoginTime(now);
user.setLastLoginIp(request.getIpAddress());
// 保存用户
userMapper.insert(user);
// 创建用户偏好设置
UserPreference preference = new UserPreference();
preference.setUserId(user.getId());
preference.setTheme("default");
preference.setLanguage("zh_CN");
preference.setNotificationEnabled(true);
preference.setPrivacyLevel(PrivacyLevel.NORMAL.getCode());
preference.setCreateTime(now);
userPreferenceMapper.insert(preference);
// 发送欢迎邮件
if (StringUtils.isNotEmpty(user.getEmail())) {
try {
Map<String, Object> model = new HashMap<>();
model.put("username", user.getUsername());
model.put("loginUrl", configService.getSystemUrl() + "/login");
emailService.sendTemplateEmail(
user.getEmail(),
"欢迎注册音乐推荐系统",
"welcome-email",
model
);
} catch (Exception e) {
log.error("发送欢迎邮件失败", e);
// 邮件发送失败不影响注册流程
}
}
// 记录用户注册日志
UserLog userLog = new UserLog();
userLog.setUserId(user.getId());
userLog.setType(LogType.REGISTER.getCode());
userLog.setContent("用户注册成功");
userLog.setIp(request.getIpAddress());
userLog.setUserAgent(request.getUserAgent());
userLog.setCreateTime(now);
userLogMapper.insert(userLog);
// 初始化用户偏好标签
if (request.getPreferredGenres() != null && !request.getPreferredGenres().isEmpty()) {
for (Long genreId : request.getPreferredGenres()) {
UserGenrePreference genrePreference = new UserGenrePreference();
genrePreference.setUserId(user.getId());
genrePreference.setGenreId(genreId);
genrePreference.setPreferenceLevel(5); // 默认中等偏好度
genrePreference.setCreateTime(now);
userGenrePreferenceMapper.insert(genrePreference);
}
}
// 返回注册结果
Map<String, Object> data = new HashMap<>();
data.put("userId", user.getId());
data.put("username", user.getUsername());
return ApiResult.success("注册成功", data);
}
```
六、基于协同过滤算法的音乐推荐系统-文档展示
七、END
💕💕文末获取源码联系计算机编程果茶熊