基于大数据的音乐推荐系统的设计与实现-程序员宅基地

技术标签: 音乐推荐  音乐推荐系统  Java  毕业设计  Hadoop  歌曲推荐  大数据  

基于大数据的音乐推荐系统是为了给听众推荐符合内心喜好的个性化系统。系统提供的功能有,音乐管理:管理员可以添加删除音乐,音乐查找:用户可以在系统中自行查找想要听的歌曲,音乐推荐:系统在收集了用户的行为数据之后为用户个性化推荐音乐,用户管理:管理员可以对用户进行删除,评论管理:管理员可以对评论进行删除,音乐下载:用户可以自行下载个人喜欢分歌曲。
本系统部署在开源大数据平台hadoop3.5之上,搭配的spark2.2也为开源免费。后端使用的关系型数据库为mysql。开发软件使用的是eclipse社区版、pycharm社区版和其他一些免费开源软件。前端采用spring和ssm,技术已经较为成熟。
目 录
摘 要 I
Abstract II
1 绪论 1
1.1 研究背景 1
1.2 研究现状 1
1.2.1 国内研究现状 1
1.2.2 国外研究现状 2
1.3 发展趋势 2
2 相关技术介绍 3
2.1 大数据环境 3
2.1.1 全球开源的Linux系统-Ubuntu 3
2.1.2 开源分大数据处理平台Hadoop 3
2.1.3 shell 3
2.1.4 kettle 4
2.1.5 Scala 4
2.2 数据获取与处理 4
2.2.1 Pymysql 4
2.2.2 Urllib.request 4
2.2.3 besutifulsoup4 4
2.3网页端 5
2.3.1 tomcat9 5
2.3.2 spring 5
3 数据采集 6
3.1 数据源确定 6
3.2 爬虫数据库设计 6
3.3 数据爬取 7
4 系统分析 15
4.1 业务分析 15
4.2 系统功能分析 16
4.3 系统可行性分析 16
4.3.1 技术可行性分析 16
4.3.2 经济可行性分析 17
4.3.3 操作性可行性分析 17
4.4 数据字典 17
4.4.1 数据项条目 17
4.4.2 数据流 19
4.4.3 数据处理条目 21
5 系统设计 23
5.1 系统总体模块结构设计 23
5.2 局部模块设计 24
5.2.1 登录注册模块 24
5.2.2 热门推荐模块 25
5.2.3 新歌上架模块 26
5.2.4 个性化推荐模块 26
5.2.5 用户中心模块 27
5.2.6 音乐管理模块 27
5.2.7 用户管理模块 28
5.2.8 评论管理模块 28
5.3 系统角色功能设计 29
5.4 推荐系统数据库设计 29
5.4.1 数据库概念结构设计 29
5.4.2 数据库物理结构设计 32
5.5 大数据平台搭建设计 35
5.5.1 hadoop的安装与配置 35
5.5.2 spark的安装 38
5.6 推荐算法设计 39
6 系统实现 46
6.1 用户界面 46
6.1.1 系统主页 46
6.1.2 用户登录 46
6.1.3 用户注册 47
6.1.4 用户登陆后界面 49
6.1.5 热门推荐界面 49
6.1.6 音乐播放详情界面 50
6.1.7 个性化音乐推荐详情界面 51
6.1.8 个人音乐记录页面 51
6.2 管理员界面 53
6.2.1 管理员登录 53
6.2.3 评论管理界面 54
6.2.4 用户管理界面 55
总结与展望 56
致 谢 57
参考文献 58
2.2 数据获取与处理
2.2.1 Pymysql
Mysql是如今最为普遍的数据库里,而python作为比较流行的语言之一,自然少不了与mysql做交互,其中pymysql就是使用最多的工具库了。Python导入pymysql之后,配置完数据库就可以直接操作数据库内各种表等。
2.2.2 Urllib.request
Urllib.request 模块定义了适用于在各种复杂情况下打开 URL(主要为 HTTP)的函数和类 — 例如基本认证、摘要认证、重定向、cookies 及其它。Requests 继承了urllib2的所有特性。Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码。Requests的文档非常完备,中文文档也相当不错。Requests能完全满足当前网络的需求,支持Python 2.6—3.8,而且能在PyPy下完美运行。
2.2.3 besutifulsoup4
HTML 文档本身是结构化的文本,有一定的规则,通过它的结构可以简化信息提取。于是,就有了lxml、pyquery、BeautifulSoup等网页信息提取库。一般会用这些库来提取网页信息。其中,lxml 有很高的解析效率,支持 xPath 语法(一种可以在 HTML 中查找信息的规则语法);pyquery 得名于 jQuery(知名的前端 js 库),可以用类似 jQuery 的语法解析网页。
BeautifulSoup(下文简称 bs)翻译成中文就是“美丽的汤”,这个奇奇怪怪的名字取自于《爱丽丝梦游仙境》,bs 最大的特点就是简单易用,不需要像正则和 xPath 等工具必须牢记很多特定的语法。虽然效率更高更直接,但对大多数 python 使用者来说,好用会比高效更重要。
2.3网页端
2.3.1 tomcat9
Tomcat是Apache Software Foundation的Jakarta项目的核心组件,该项目是由Apache,Sun和一些公司和个人开发的轻量级Web应用程序服务器。是Servlet和JSP规范的开源实现。由于其技术非常先进,而且工作稳且性能高,它深受java爱好者的追捧,很多开源边界者都对他赞赏有加。目前呢已经成为最流行流行的Web应用程序服务器。
2.3.2 spring
Spring框架是Rod Johnson启动的开源J2EE应用程序框架,而Rod Johnson是用于bean生命周期管理的轻量级容器。 Spring解决了J2EE开发过程中开发人员遇到的较多常见问题,还提供了非常实用的功能,例如IOC,AOP,Web MVC等。 Spring甚至可以单独构建,也可以与Struts,Webwork和Tapstry等桌面应用程序结合以创建JEE,桌面和小型应用程序。
3 数据采集
3.1 数据源确定
确定了要做基于大数据的音乐推荐系统之后,首先要确定数据源。通过分析基于大数据的音乐推荐系统,即音乐推荐需要哪些数据,详细了解推荐机制,搞清楚这些数据需要被处理为什么格式。
首先定义爬取目标:
1.实现音乐的个性化推荐,帮助用户快速找到可能感兴趣的音乐。
2.实现音乐的热门推荐,帮助主流大众迅速找到流行的趋势。
3.实现音乐的新品推荐,帮助唱片公司带动市场,实现引流。
各大音乐网站多如牛毛,确定了数据爬取目标之后,接下来要确定去哪个平台去爬取泽泻数据。选择数据源要确定数据源数据是否可靠真实,要避免爬取音乐平台发布的虚伪的音乐数据,如不存在的歌唱家、专辑、音乐等。
于是,在比较多家音乐平台(QQ音乐、网易云音乐、酷狗音乐、酷音乐)后,综合分析后选择网易云音乐网页版作为爬虫目标。基于之前设定的爬取目标,选择爬取以下数据:
1.歌手信息:歌手id,歌手名字
2.歌手专辑信息:专辑id,专辑名称,专辑封面
3.音乐信息:音乐名

歌曲推荐算法

package top.wangruns.trackstacking.algorithm;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

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

}

获取歌曲信息代码:

package top.wangruns.trackstacking.algorithm;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

import top.wangruns.trackstacking.model.Collection;
import top.wangruns.trackstacking.model.DownloadRecord;
import top.wangruns.trackstacking.model.PlayRecord;
import top.wangruns.trackstacking.model.User;

public class DataTranslate {
    
	private final static float PLAY_SCORE=1f;
	private final static float DOWNLOAD_SCORE=2f;
	private final static float COLLECTION_SCORE=5f;
	private final static float MAX_SCORE=10f;
	private final static int SONG_ID_SET_KEY=0;

	/**
	 * 构建用户频率矩阵来近似用户评分,对于某些系统而言,我们是不可能获取到用户对某些项目的评分的,但是我们可以利用用户的
	 * 行为习惯来反映用户的“评分”,比如一个用户常常收听某一首歌,那么我们可以推断该用户喜欢该歌曲的可能性很大.
	 * 总分10分,主动播放一次1分,下载2分,收藏5分,如果超过10分,按10分计算.
	 * @param userIdList 
	 * 用户Id列表
	 * @param songIdList 
	 * 歌曲Id列表
	 * @param downloadList
	 * 用户的下载记录列表
	 * @param playList
	 * 用户的播放记录列表
	 * @param collectionList
	 * 用户的收藏记录列表
	 * @return
	 * 用户Id-歌曲Id 频率矩阵
	 */
	public static Map<Integer, float[]> getFrequencyMatrix(List<Integer> userIdList, final List<Integer> songIdList,
			List<DownloadRecord> downloadList, List<PlayRecord> playList, List<Collection> collectionList) {
    
		// TODO Auto-generated method stub
		final Map<Integer,float[]> user2songRatingMatrix=new HashMap<Integer, float[]>();
		final int songLen=songIdList.size();
		//获取用户-歌曲 下载映射
		final Map<Integer,Map<Integer,Set<Integer>>> userId2songIdDownloadMap=getUserId2songIdRecordMap(downloadList,false);
		//获取用户-歌曲 收藏映射
		final Map<Integer, Map<Integer, Set<Integer>>> userId2songIdCollectionMap=getUserId2songIdRecordMap(collectionList,false);
		//获取用户-歌曲-次数 播放映射
		final Map<Integer, Map<Integer, Set<Integer>>> userId2songIdPlayMap=getUserId2songIdRecordMap(playList,true);
		
		userIdList.forEach(new Consumer<Integer>() {
    

			public void accept(Integer userId) {
    
				// TODO Auto-generated method stub
				float[] curUserRatingArray=new float[songLen];
				int songIndex=0;
				//处理每一首歌曲
				for(Integer songId:songIdList) {
    
					/**
					 * 处理下载,这里不考虑下载次数
					 */
					if(userId2songIdDownloadMap.get(userId)!=null && userId2songIdDownloadMap.get(userId).get(SONG_ID_SET_KEY).contains(songId)) {
    
						//当前用户下载过的歌曲
						curUserRatingArray[songIndex]+=DOWNLOAD_SCORE;
					}
					
					/**
					 * 处理收藏,这里没有次数
					 */
					if(userId2songIdCollectionMap.get(userId)!=null && userId2songIdCollectionMap.get(userId).get(SONG_ID_SET_KEY).contains(songId)) {
    
						//当前用户收藏的歌曲
						curUserRatingArray[songIndex]+=COLLECTION_SCORE;
					}
					
					/**
					 * 处理播放,考虑播放次数
					 */
					if(userId2songIdPlayMap.get(userId)!=null && userId2songIdPlayMap.get(userId).get(SONG_ID_SET_KEY).contains(songId)) {
    
						//当前用户播放过的歌曲
						int count=userId2songIdPlayMap.get(userId).get(songId).iterator().next();
						curUserRatingArray[songIndex]+=PLAY_SCORE + count;
					}
					
					/**
					 * 处理最大得分,超过最大得分,记为最大得分
					 */
					if(curUserRatingArray[songIndex]>MAX_SCORE) {
    
						curUserRatingArray[songIndex]=MAX_SCORE;
					}
					//处理下一首歌
					songIndex++;
				}
				//处理完一个用户
				user2songRatingMatrix.put(userId, curUserRatingArray);
			}
			
		});
		return user2songRatingMatrix;
	}

	/**
	 * 获取用户Id - 歌曲Id 的映射Map
	 * @param recordList
	 * 包含userId,songId的记录列表
	 * @param isCount
	 * 是否需要计数。如果true,则Integer[1]存放计数。
	 * @return
	 * 两层Map
	 * 第一层Map<Integer,Map> 每个userId拥有一个自己的Map:
	 * userId,userSetMap
	 * 
	 * 第二层Map<Integer,Set> 用户自己的Map里面存放两个东西:
	 * (1)为每首歌曲计数songId,CountSet;
	 * (2)存放出现过的歌曲songSetFlay,SongIdSet:
	 */
	private static <T> Map<Integer, Map<Integer, Set<Integer>>> getUserId2songIdRecordMap(final List<T> recordList,final boolean isCount) {
    
		// TODO Auto-generated method stub
		final Map<Integer, Map<Integer, Set<Integer>>> userId2songIdRecordMap=new HashMap<Integer, Map<Integer, Set<Integer>>>();
		
		recordList.forEach(new Consumer<T>() {
    

			public void accept(T t) {
    
				// TODO Auto-generated method stub
				try {
    
					//利用反射获和泛型获取不同类型表的相同属性
					Field userIdField=t.getClass().getDeclaredField("userId");
					Field songIdField=t.getClass().getDeclaredField("songId");
					userIdField.setAccessible(true);
					songIdField.setAccessible(true);
					int userId=userIdField.getInt(t);
					int songId=songIdField.getInt(t);
					//不需要计数
					if(!isCount) {
    
						//map外层的userId已经存在
						if(userId2songIdRecordMap.containsKey(userId)) {
    
							//获取当前用户的记录集合Map
							Map<Integer,Set<Integer>> curRecordSetMap=userId2songIdRecordMap.get(userId);
							//将当前歌曲添加到当前用户的记录集合中
							curRecordSetMap.get(SONG_ID_SET_KEY).add(songId);
						}else {
    
							Map<Integer,Set<Integer>> curRecordSetMap=new HashMap<Integer, Set<Integer>>();
							//创建记录歌曲Id的集合
							Set<Integer> curSongIdSet=new HashSet<Integer>();
							curSongIdSet.add(songId);
							curRecordSetMap.put(SONG_ID_SET_KEY, curSongIdSet);
							userId2songIdRecordMap.put(userId, curRecordSetMap);
						}
					}else {
    
						//map外层的userId已经存在
						if(userId2songIdRecordMap.containsKey(userId)) {
    
							//获取当前用户的记录集合Map
							Map<Integer,Set<Integer>> curRecordSetMap=userId2songIdRecordMap.get(userId);
							//将当前歌曲添加到当前用户的记录集合中
							curRecordSetMap.get(SONG_ID_SET_KEY).add(songId);
							
							//计数
							count(songId,curRecordSetMap);
							
						}else {
    
							Map<Integer,Set<Integer>> curRecordSetMap=new HashMap<Integer, Set<Integer>>();
							//创建记录歌曲Id的集合
							Set<Integer> curSongIdSet=new HashSet<Integer>();
							curSongIdSet.add(songId);
							curRecordSetMap.put(SONG_ID_SET_KEY, curSongIdSet);
							userId2songIdRecordMap.put(userId, curRecordSetMap);
							
							//计数
							count(songId,curRecordSetMap);
							
						}
					}
					
				}catch (NoSuchFieldException e) {
    
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
    
					e.printStackTrace();
				} catch (IllegalAccessException e) {
    
					e.printStackTrace();
				}
			}

			private void count(int songId, Map<Integer, Set<Integer>> curRecordSetMap) {
    
				// TODO Auto-generated method stub
				/**
				 * 计数,如果Map<songId,count>已经存在,则直接计数+1
				 */
				if(curRecordSetMap.containsKey(songId)) {
    
					//获取当前用户歌曲的计数集合(只有一个元素)
					Set<Integer> curCountSet=curRecordSetMap.get(songId);
					int cnt=curCountSet.iterator().next()+1;
					curCountSet.clear();
					curCountSet.add(cnt);
				}else {
    
					Set<Integer> curCountSet=new HashSet<Integer>();
					curCountSet.add(1);
					curRecordSetMap.put(songId, curCountSet);
				}
			}
			
			
		});
		return userId2songIdRecordMap;
	}

//	private static Map<Integer, Integer>getUserId2songIdDownloadMap(List<DownloadRecord> downloadList) {
    
//		// TODO Auto-generated method stub
//		final Map<Integer,Integer> userId2songIdDownloadMap=new HashMap<Integer, Integer>();
//		downloadList.forEach(new Consumer<DownloadRecord>() {
    
//
//			public void accept(DownloadRecord t) {
    
//				// TODO Auto-generated method stub
//				if(!userId2songIdDownloadMap.containsKey(t.getUserId())) {
    
//					userId2songIdDownloadMap.put(t.getUserId(), t.getSongId());
//				}
//			}
//			
//		});
//		return userId2songIdDownloadMap;
//	}
	

}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/newlw/article/details/125674127

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法