基于spring+mysql实现的音乐推荐系统
1.项目简介
本音乐网站的开发主要利用 spring 框架开发后台,前端采用 Boostrap+jsp 实现,数据库使用的是 MySQL。
1.1 系统功能模块结构
1.2 用户模块功能描述
其中,用户信息管理以及订单是禁止匿名用户访问的内容。
-
用户信息模块 :注册新用户、登录、用户修改密码、用户个人资料管理
-
用户留言模块 :用户可以在喜欢的歌曲下留言与其他听众交流
-
歌曲清单模块 :热门歌曲浏览、新歌浏览(首页显示最新发表的歌曲列表)、歌曲分类浏览、按歌曲名称搜索、商品详细信息
-
喜欢的歌曲模块 :添加喜欢的歌曲到自己专属的歌单
1.3 管理模块功能描述
-
用户管理 :登录;查询用户、删除用户
-
歌曲管理 :添加、修改、删除歌曲信息
2.数据库设计
2.1 表结构
收藏列表表
下载信息表
喜欢表
播放表
个性化表
最近播放表
权限表
用户表
歌曲表
用户权限表
2.2 E-R图
3.项目实现
3.1 加密处理
```java public class MD5Util {
/**
* MD5 生成32位md5码
* @param inStr
* 需要加密的字符串
* @return
*/
public static String string2MD5(String inStr){
MessageDigest md5 = null;
try{
md5 = MessageDigest.getInstance("MD5");
}catch (Exception e){
System.out.println(e.toString());
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++){
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
} ```
3.2 定时任务配置
```java public class Static { /* * 用于记录,两张个性化推荐列表,isFromA为true表示,从表A中读取数据; * 否则从表B中读取. * 每天早上6点,两张表交替更新 / public static volatile boolean isFromA=true;
/**
* 更新个性化推荐列表的时间间隔(这里每天更新一次)
*/
public static final long PERIOD_DAY = 24 * 60 * 60 * 1000;
/**
* 更新开始的时间:时
*/
public static final int START_HOUR = 6;
/**
* 更新开始的时间:分
*/
public static final int START_MINUTE = 0;
/**
* 更新开始的时间:秒
*/
public static final int START_SECOND = 0;
/**
* 更新是否从明天开始
*/
public static final boolean IS_START_TOMORROW = false;
/**
* KNN k值
* 目前系统用户很少
*/
public static final int K = 2;
/**
* 基于最近邻用户的协同过滤给用户推荐歌曲的数量 n值
* 歌曲很少
*/
public static final int N = 10;
/**
* 排行榜的,每日一词
*/
public static final String [] RANKING_WORD_ARRAY= {"百尺竿头","步步高升","精益求精", "登堂入室","登峰造极","泰山北斗","功成名就","大展鸿图","炉火纯青"};
/**
* 我的音乐的,每日一词
*/
public static final String [] MY_MUSIC_WORD_ARRAY= {"四面楚歌","余音绕梁","靡靡之音", "扣人心弦","高山流水","四面楚歌","曲高和寡","余音袅袅","一唱三叹","四面楚歌","绕梁三日","游鱼出听"};
/**
* 搜索结果,每次一词
*/
public static final String [] SEARCH_WORD_ARRAY= {"众里寻他","计获事足","望眼欲穿", "踏破铁鞋","如愿以偿","东寻西觅","摸索门径","寻踪觅迹"};
/**
* 是否开启混合模式,英文歌词文件较少的情况下建议关闭
* 基于最近邻用户的协同过滤 + 基于异构文本网络的嵌入
* 这里采取简单拼接的混合策略
*/
public static final boolean IS_HYBRID=false;
/**
* 基于异构文本网络给用户推荐歌曲的数量 n值
* 歌曲很少很少
*/
public static final int N_HYBRID = 1;
} ```
3.3 编写功能实现代码
```java @Service("songService") public class SongServiceImpl implements SongService{ @Autowired private SongDao songDao; @Autowired private UserDao userDao; @Autowired private TrendingRecDao trendingRecDao;
public List<Integer> getAllSongIdRecords() {
return songDao.selectAllSongId();
}
public Song getSongById(int songId) {
return songDao.selectSongById(songId);
}
public Song getSongByIdWithCollectionFlag(HttpServletRequest request, int songId) {
//获取对应Id的歌曲
Song song=songDao.selectSongById(songId);
if(song==null) {
return null;
}
//获取对应Id的歌曲的流行度
int trendingCoefficient=songDao.selectCoefficientById(songId);
song.setTrendingCoefficient(trendingCoefficient);
//获取用户的收藏列表
List<Collection> collectionList=new ArrayList<Collection>();
User user=userDao.selectByUser(Request.getUserFromHttpServletRequest(request));
collectionList=trendingRecDao.getCollection(user);
if(collectionList!=null) {
for(Collection c:collectionList) {
if(c.getSongId()==songId) {
song.setWhetherCollected(true);
break;
}
}
}
return song;
}
public void batchDeleteById(HttpServletRequest request,int[] songIds) {
if(songIds==null) {
return;
}
for(int id:songIds) {
Song song=songDao.selectSongById(id);
if(song!=null) {
String realSongPath=request.getServletContext().getRealPath(song.getSongAddress());
File fileSong=new File(realSongPath);
fileSong.delete();
if(song.getLyricAddress()!=null) {
String realLyricPath=request.getServletContext().getRealPath(song.getLyricAddress());
File fileLyric=new File(realLyricPath);
fileLyric.delete();
}
}
}
songDao.deleteByIds(songIds);
}
/**
* 这里由于在前端文件上传的时候,已经做过验证了,所以后端这里不再次验证了
* 由于时间关系,这里默认前端的验证是可靠的,虽然有时候这是一种危险的做法
*/
public boolean checkFormat(MultipartFile song, MultipartFile lyric) {
return true;
}
public boolean addSong(HttpServletRequest request,MultipartFile song, MultipartFile lyric) {
String name=song.getOriginalFilename();
//歌曲名称需去掉.mp3的后缀
String songName=name.substring(0, name.lastIndexOf("."));
String songAddress="track/song/"+name;
boolean isInsertSuccessful=false;
int affectedRows=-1;
//歌词文件是可选的
if(lyric.isEmpty()) {
affectedRows=songDao.insertOnlySong(new Song(songName,songAddress));
//保存歌曲文件
saveFile(song,request.getServletContext().getRealPath(songAddress));
}else {
//这里的歌曲名称仍旧保留.lrc的后缀
String lyricName=lyric.getOriginalFilename();
String lyricAddress="track/lyric/"+lyricName;
affectedRows=songDao.insertSongWithLyric(new Song(songName,songAddress,lyricName,lyricAddress));
//保存歌曲文件
saveFile(song,request.getServletContext().getRealPath(songAddress));
//保存歌词文件
saveFile(lyric,request.getServletContext().getRealPath(lyricAddress));
}
if(affectedRows>0) {
isInsertSuccessful=true;
}
return isInsertSuccessful;
}
private void saveFile(MultipartFile multipartFile, String realFilePath) {
try {
InputStream inputStream=multipartFile.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(realFilePath);
try {
int b = 0;
while ((b = inputStream.read()) != -1) {
fileOutputStream.write(b);
}
}finally{
inputStream.close();
fileOutputStream.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public List<Song> getAllSongRecordsWithLyric() {
return songDao.selectAllSongsWithLyric();
}
} ```
CollaborativeFiltering.java
java
public class CollaborativeFiltering {
/**
* 基于最近邻用户产生协同过滤的推荐结果
* @param userIdList
* 用户Id列表
* @param userKNNMatrix
* 用户KNN矩阵
* @param user2songRatingMatrix
* 用户歌曲“评分”矩阵
* @param songIdList
* 歌曲Id列表
* @param n
* 推荐的前n首歌曲
* @return
* 用户歌曲推荐结果矩阵.userId,[recSongId1,recSongId2...recSongIdn]
*/
public static Map<Integer, Integer[]> userKNNBasedCF(List<Integer> userIdList,
final Map<Integer, Integer[]> userKNNMatrix, final Map<Integer, float[]> user2songRatingMatrix,
final List<Integer> songIdList, final int n) {
// TODO Auto-generated method stub
final Map<Integer,Integer[]> user2songRecMatrix=new HashMap<Integer, Integer[]>();
userIdList.forEach(new Consumer<Integer>() {
public void accept(Integer curUserId) {
// TODO Auto-generated method stub
Integer[] knnIdArray=userKNNMatrix.get(curUserId);
/**
* 对于每一首当前用户没有听过的歌曲
* 协同得分为:
* 其k个最近邻用户对该歌曲的“评分”的聚合
*/
float[] curUserRatings=user2songRatingMatrix.get(curUserId);
//为用户建立一个最小堆来存放最高的前n首歌曲
MininumHeap mininumHeap=new MininumHeap(n);
for(int i=0;i<curUserRatings.length;i++) {
//对于没有听过的歌曲
/**
* 这里需要注意的是,浮点数不能用==来比较...之前竟然犯了这个低级的错误...
* 故这里用 curUserRatings[i]<0.01f 来表示 curUserRatings[i]==0f
*/
if(curUserRatings[i]<0.01f) {
for(int knnIndex=0;knnIndex<knnIdArray.length;knnIndex++) {
int knnId=knnIdArray[knnIndex];
float[] knnUserRatings=user2songRatingMatrix.get(knnId);
curUserRatings[i]+=knnUserRatings[i];
}
//这里的聚合策略取均值
curUserRatings[i]/=knnIdArray.length;
int curSongId=songIdList.get(i);
//放入堆中
mininumHeap.addElement(new TreeNode(curSongId,curUserRatings[i]));
}
}
/**
* 对该用户没有听过的歌曲,协同得分完成,选取n个得分最高的项目作为推荐
*/
int trueNumber=n;
//如果推荐的歌曲少于计划推荐的n首(处理歌曲很少的情况)
if(mininumHeap.getCurHeapSize()<n) {
trueNumber=mininumHeap.getCurHeapSize();
}
Integer[] curUserRecSongId=new Integer[trueNumber];
for(int i=0;i<trueNumber;i++) {
int recSongId=mininumHeap.getArray()[i].id;
curUserRecSongId[i]=recSongId;
}
user2songRecMatrix.put(curUserId, curUserRecSongId);
});
return user2songRecMatrix;
}
}
3.5 功能实现
-
音乐播放
-
用户登录注册
-
用户信息编辑、头像修改
-
歌曲、歌单搜索
-
歌单打分
-
歌单、歌曲评论
-
歌单列表、歌手列表分页显示
-
歌词同步显示
-
音乐收藏、下载、拖动控制、音量控制
-
后台对用户、歌曲、歌手、歌单信息的管理
4.项目展示
首页
登录与注册
5.安装
5.1 下载数据库中记录的资源
去【链接: https://pan.baidu.com/s/1Qv0ohAIPeTthPK_CDwpfWg 提取码: gwa4 】下载网站依赖的歌曲及图片,将 data 夹里的文件直接放到 music-server 文件夹下。
5.2 修改配置文件
- 创建数据库
-
将 music/music-server/sql 文件夹中的 tp_music.sql 文件导入数据库。
-
修改后端配置文件
- 在 music/music-server/src/main/resources 这个目录下的文件里修改自己的 spring.datasource.username 和 spring.datasource.password
参考文献
- 个性化音乐推荐系统的设计与实现(华中科技大学·游聪)
- 基于用户行为的音乐推荐系统设计与实现(华中科技大学·郝陆风)
- 移动端音乐Web APP的设计与实现(华中科技大学·金旻)
- 融合知识图谱的个性化推荐系统设计与实现(天津工业大学·郭峰)
- 基于潜在因子模型的音乐推荐系统研究(山东科技大学·肖海峰)
- 基于PHP的在线音乐网站的设计与实现(武汉理工大学·陈君)
- 基于潜在因子模型的音乐推荐系统研究(山东科技大学·肖海峰)
- 个性化音乐推荐系统(电子科技大学·曾凡聪)
- 基于排序学习的音乐推荐系统设计与实现(重庆大学·魏斌)
- 基于排序学习的音乐推荐系统设计与实现(重庆大学·魏斌)
- 手机应用推荐程序后台支撑系统设计与实现(北京交通大学·陈昊龙)
- 基于情感分析的个性化音乐推荐系统的设计与实现(曲阜师范大学·毛庆航)
- CLARANS改进算法在音乐网站智能推荐系统中的应用(吉林大学·魏佳)
- 融合HMM及歌曲特征标签的混合推荐算法研究(江西师范大学·李春俊)
- 基于流式大数据的音乐推荐系统的设计与实现(华中科技大学·何鹏飞)
本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:代码助手 ,原文地址:https://bishedaima.com/yuanma/35457.html