基于spring+mysql实现的音乐推荐系统

基于spring+mysql实现的音乐推荐系统 1,项目简介 本音乐网站的开发主要利用 spring 框架开发后台,前端采用 Boostrap+jsp 实现

本文包含相关资料包-----> 点击直达获取<-------

基于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

相关推荐

发表回复

登录后才能评论