基于Boostrap+jsp+spring+mysql的音乐推荐系统

1.项目简介

本音乐网站的开发主要利用 spring 框架开发后台,前端采用 Boostrap+jsp 实现,数据库使用的是 MySQL。

1.2 用户模块功能描述

其中,用户信息管理以及订单是禁止匿名用户访问的内容。

  • 用户信息模块:注册新用户、登录、用户修改密码、用户个人资料管理

  • 用户留言模块:用户可以在喜欢的歌曲下留言与其他听众交流

  • 歌曲清单模块:热门歌曲浏览、新歌浏览(首页显示最新发表的歌曲列表)、歌曲分类浏览、按歌曲名称搜索、商品详细信息

  • 喜欢的歌曲模块:添加喜欢的歌曲到自己专属的歌单

1.3 管理模块功能描述

  • 用户管理:登录;查询用户、删除用户

  • 歌曲管理:添加、修改、删除歌曲信息

3.项目实现

3.1 加密处理

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 定时任务配置

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 编写功能实现代码

@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);
	}


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.项目展示


基于Boostrap+jsp+spring+mysql的音乐推荐系统_第1张图片
基于Boostrap+jsp+spring+mysql的音乐推荐系统_第2张图片
基于Boostrap+jsp+spring+mysql的音乐推荐系统_第3张图片
基于Boostrap+jsp+spring+mysql的音乐推荐系统_第4张图片
基于Boostrap+jsp+spring+mysql的音乐推荐系统_第5张图片

基于Boostrap+jsp+spring+mysql的音乐推荐系统_第6张图片
基于Boostrap+jsp+spring+mysql的音乐推荐系统_第7张图片
基于Boostrap+jsp+spring+mysql的音乐推荐系统_第8张图片
基于Boostrap+jsp+spring+mysql的音乐推荐系统_第9张图片
基于Boostrap+jsp+spring+mysql的音乐推荐系统_第10张图片

你可能感兴趣的:(java,spring,mysql,音乐推荐系统,协同过滤算法)