php 将图片保存为不同尺寸的图片类的简单示例

对一个php图片类,将图片保存为不同尺寸的图片感兴趣的小伙伴,下面一起跟随编程之家 jb51.cc的小编两巴掌来看看吧!

<?php
/**
 * 一个php图片类,将图片保存为不同尺寸的图片
 *
 * @param 
 * @arrange 网: www.www.jb51.cc
 **/
/**
 图片处理类
 */
class imagecls
{
 /**
  * 文件信息
  */
 var $file = array();
 /**
  * 保存目录
  */
 var $dir = '';
 /**
  * 错误代码
  */
 var $error_code = 0;
 /**
  * 文件上传最大KB
  */
 var $max_size = -1;
 function es_imagecls()
 {
 }
	private function checkSize($size)
	{
		return !($size > $this->max_size) || (-1 == $this->max_size);
	}
 /**
  * 处理上传文件
  * @param array $file 上传的文件
  * @param string $dir 保存的目录
  * @return bool
  */
 function init($file,$dir = 'temp')
 {
  if(!is_array($file) || empty($file) || !$this->isUploadFile($file['tmp_name']) || trim($file['name']) == '' || $file['size'] == 0)
  {
   $this->file = array();
   $this->error_code = -1;
   return false;
  }
  else
  {
   $file['size'] = intval($file['size']);
   $file['name'] =  trim($file['name']);
   $file['thumb'] = '';
   $file['ext'] = $this->fileExt($file['name']);
   $file['name'] =  htmlspecialchars($file['name'],ENT_QUOTES);
   $file['is_image'] = $this->isImageExt($file['ext']);
   $file['file_dir'] = $this->getTargetDir($dir);
   $file['prefix'] = md5(microtime(true)).rand(10,99);
   $file['target'] = ./public/.$file['file_dir'].'/'.$file['prefix'].'.jpg';  //相对
   $file['local_target'] = APP_ROOT_PATH.public/.$file['file_dir'].'/'.$file['prefix'].'.jpg';  //物理
   $this->file = &$file;
   $this->error_code = 0;
   return true;
  }
 }
 /**
  * 保存文件
  * @return bool
  */
 function save()
 {
  if(empty($this->file) || empty($this->file['tmp_name']))
   $this->error_code = -101;
  elseif(!$this->checkSize($this->file['size']))
   $this->error_code = -105;
  elseif(!$this->file['is_image'])
   $this->error_code = -102;
  elseif(!$this->saveFile($this->file['tmp_name'],$this->file['local_target']))
   $this->error_code = -103;
  elseif($this->file['is_image'] && (!$this->file['image_info'] = $this->getImageInfo($this->file['local_target'],true)))
  {
   $this->error_code = -104;
   @unlink($this->file['local_target']);
  }
  else
  {
   $this->error_code = 0;
   return true;
  }
  return false;
 }
 /**
  * 获取错误代码
  * @return number
  */
 function error()
 {
  return $this->error_code;
 }
 /**
  * 获取文件扩展名
  * @return string
  */
 function fileExt($file_name)
 {
  return addslashes(strtolower(substr(strrchr($file_name,'.'),1,10)));
 }
 /**
  * 根据扩展名判断文件是否为图像
  * @param string $ext 扩展名
  * @return bool
  */
 function isImageExt($ext)
 {
  static $img_ext  = array('jpg','jpeg','png','bmp','gif','giff');
  return in_array($ext,$img_ext) ? 1 : 0;
 }
 /**
  * 获取图像信息
  * @param string $target 文件路径
  * @return mixed
  */
 function getImageInfo($target)
 {
  $ext = es_imagecls::fileExt($target);
  $is_image = es_imagecls::isImageExt($ext);
  if(!$is_image)
   return false;
  elseif(!is_readable($target))
   return false;
  elseif($image_info = @getimagesize($target))
  {
   list($width,$height,$type) = !empty($image_info) ? $image_info : array('','','');
   $size = $width * $height;
   if($is_image && !in_array($type,array(1,2,3,6,13)))
	return false;
   $image_info['type'] = strtolower(substr(image_type_to_extension($image_info[2]),1));
   return $image_info;
  }
  else
   return false;
 }
 /**
  * 获取是否充许上传文件
  * @param string $source 文件路径
  * @return bool
  */
 function isUploadFile($source)
 {
  return $source && ($source != 'none') && (is_uploaded_file($source) || is_uploaded_file(str_replace('\\\\','\\',$source)));
 }
 /**
  * 获取保存的路径
  * @param string $dir 指定的保存目录
  * @return string
  */
 function getTargetDir($dir)
 {       
		if (!is_dir(APP_ROOT_PATH.public/.$dir)) { 
			 @mkdir(APP_ROOT_PATH.public/.$dir);
			 @chmod(APP_ROOT_PATH.public/.$dir,0777);
		}
		return $dir;
 }
 /**
  * 保存文件
  * @param string $source 源文件路径
  * @param string $target 目录文件路径
  * @return bool
  */
 private function saveFile($source,$target)
 {
  if(!es_imagecls::isUploadFile($source))
   $succeed = false;
  elseif(@copy($source,$target))
   $succeed = true;
  elseif(function_exists('move_uploaded_file') && @move_uploaded_file($source,$target))
   $succeed = true;
  elseif (@is_readable($source) && (@$fp_s = fopen($source,'rb')) && (@$fp_t = fopen($target,'wb')))
  {
   while (!feof($fp_s))
   {
	$s = @fread($fp_s,1024 * 512);
	@fwrite($fp_t,$s);
   }
   fclose($fp_s);
   fclose($fp_t);
   $succeed = true;
  }
  if($succeed)
  {
   $this->error_code = 0;
   @chmod($target,0644);
   @unlink($source);
  }
  else
  {
   $this->error_code = 0;
  }
  return $succeed;
 }
 public function thumb($image,$maxWidth=200,$maxHeight=50,$gen = 0,$interlace=true,$filepath = '',$is_preview = true)
	{
		$info  = es_imagecls::getImageInfo($image);
		if($info !== false)
  {
			$srcWidth  = $info[0];
			$srcHeight = $info[1];
   $type = $info['type'];
			$interlace  =  $interlace? 1:0;
			unset($info);
   if($maxWidth > 0 && $maxHeight > 0)
	$scale = min($maxWidth/$srcWidth,$maxHeight/$srcHeight); // 计算缩放比例
   elseif($maxWidth == 0)
	$scale = $maxHeight/$srcHeight;
   elseif($maxHeight == 0)
	$scale = $maxWidth/$srcWidth;
   $paths = pathinfo($image);
   $paths['filename'] = trim(strtolower($paths['basename']),..strtolower($paths['extension']));
   $basefilename = explode(_,$paths['filename']);
   $basefilename = $basefilename[0];
   if(empty($filepath))
   {
	if($is_preview)
	$thumbname = $paths['dirname'].'/'.$basefilename.'_'.$maxWidth.'x'.$maxHeight.'.jpg';
	else
	$thumbname = $paths['dirname'].'/'.$basefilename.'o_'.$maxWidth.'x'.$maxHeight.'.jpg';
   }
   else
	$thumbname = $filepath;
   $thumburl = str_replace(APP_ROOT_PATH,'./',$thumbname);
			if($scale >= 1)
   {
				// 超过原图大小不再缩略
				$width   =  $srcWidth;
				$height  =  $srcHeight;         
				if(!$is_preview)
				{       
				 //非预览模式写入原图
				 file_put_contents($thumbname,file_get_contents($image));    //用原图写入            
				 return array('url'=>$thumburl,'path'=>$thumbname);
				}
			}
   else
   {
				// 缩略图尺寸
				$width  = (int)($srcWidth*$scale);
				$height = (int)($srcHeight*$scale);
			}  
   if($gen == 1)
   {
	$width = $maxWidth;
	$height = $maxHeight;
   }
			// 载入原图
			$createFun = 'imagecreatefrom'.($type=='jpg'?'jpeg':$type);
   if(!function_exists($createFun))
	$createFun = 'imagecreatefromjpeg';
			$srcImg = $createFun($image);
			//创建缩略图
			if($type!='gif' && function_exists('imagecreatetruecolor'))
				$thumbImg = imagecreatetruecolor($width,$height);
			else
				$thumbImg = imagecreate($width,$height);
   $x = 0;
   $y = 0;
   if($gen == 1 && $maxWidth > 0 && $maxHeight > 0)
   {
	$resize_ratio = $maxWidth/$maxHeight;
	$src_ratio = $srcWidth/$srcHeight;
	if($src_ratio >= $resize_ratio)
	{
	 $x = ($srcWidth - ($resize_ratio * $srcHeight)) / 2;
	 $width = ($height * $srcWidth) / $srcHeight;
	}
	else
	{
	 $y = ($srcHeight - ( (1 / $resize_ratio) * $srcWidth)) / 2;
	 $height = ($width * $srcHeight) / $srcWidth;
	}
   }
			// 复制图片
			if(function_exists(imagecopyresampled))
				imagecopyresampled($thumbImg,$srcImg,$x,$y,$width,$srcWidth,$srcHeight);
			else
				imagecopyresized($thumbImg,$srcHeight);
			if('gif'==$type || 'png'==$type) {
				$background_color  =  imagecolorallocate($thumbImg,255,0);  //  指派一个绿色
	imagecolortransparent($thumbImg,$background_color);  //  设置为透明色,若注释掉该行则输出绿色的图
			}
			// 对jpeg图形设置隔行扫描
			if('jpg'==$type || 'jpeg'==$type)
	imageinterlace($thumbImg,$interlace);
			// 生成图片
			imagejpeg($thumbImg,$thumbname,100);
			imagedestroy($thumbImg);
			imagedestroy($srcImg);
   return array('url'=>$thumburl,'path'=>$thumbname);
		 }
		 return false;
	}
 public function make_thumb($srcImg,$srcHeight,$type,$gen = 0)
	{
			$interlace  =  $interlace? 1:0;
   if($maxWidth > 0 && $maxHeight > 0)
	$scale = min($maxWidth/$srcWidth,$maxHeight/$srcHeight); // 计算缩放比例
   elseif($maxWidth == 0)
	$scale = $maxHeight/$srcHeight;
   elseif($maxHeight == 0)
	$scale = $maxWidth/$srcWidth;
			if($scale >= 1)
   {
				// 超过原图大小不再缩略
				$width   =  $srcWidth;
				$height  =  $srcHeight;
			}
   else
   {
				// 缩略图尺寸
				$width  = (int)($srcWidth*$scale);
				$height = (int)($srcHeight*$scale);
			}
   if($gen == 1)
   {
	$width = $maxWidth;
	$height = $maxHeight;
   }
			//创建缩略图
			if($type!='gif' && function_exists('imagecreatetruecolor'))
				$thumbImg = imagecreatetruecolor($width,$height);
			else
				$thumbImg = imagecreatetruecolor($width,255);  //  指派一个绿色
	imagecolortransparent($thumbImg,$interlace);
		   return $thumbImg;
	}
 public function water($source,$water,$alpha=80,$position=0)
	{
		//检查文件是否存在
		if(!file_exists($source)||!file_exists($water))
			return false;
		//图片信息
		$sInfo = es_imagecls::getImageInfo($source);
		$wInfo = es_imagecls::getImageInfo($water);
		//如果图片小于水印图片,不生成图片
		if($sInfo[0] < $wInfo[0] || $sInfo['1'] < $wInfo['1'])
			return false;
		if(is_animated_gif($source))
		{
		 require_once APP_ROOT_PATH.system/utils/gif_encoder.php;
   require_once APP_ROOT_PATH.system/utils/gif_reader.php;
   $gif = new GIFReader();
   $gif->load($source);
   foreach($gif->IMGS['frames'] as $k=>$img)
   {
	$im = imagecreatefromstring($gif->getgif($k));  
	//为im加水印
	$sImage=$im;  
		  $wCreateFun=imagecreatefrom.$wInfo['type'];
	if(!function_exists($wCreateFun))
	 $wCreateFun = 'imagecreatefromjpeg';
		  $wImage=$wCreateFun($water);
		  //设定图像的混色模式
		  imagealphablending($wImage,true);  
		  switch (intval($position))
		  {
		   case 0: break;
		   //左上
		   case 1:
			$posY=0;
			$posX=0;
			//生成混合图像
			imagecopymerge($sImage,$wImage,$posX,$posY,$wInfo[0],$wInfo[1],$alpha);
			break;
		   //右上
		   case 2:
			$posY=0;
			$posX=$sInfo[0]-$wInfo[0];
			//生成混合图像
			imagecopymerge($sImage,$alpha);
			break;
		   //左下
		   case 3:
			$posY=$sInfo[1]-$wInfo[1];
			$posX=0;
			//生成混合图像
			imagecopymerge($sImage,$alpha);
			break;
		   //右下
		   case 4:
			$posY=$sInfo[1]-$wInfo[1];
			$posX=$sInfo[0]-$wInfo[0];
			//生成混合图像
			imagecopymerge($sImage,$alpha);
			break;
		   //居中
		   case 5:
			$posY=$sInfo[1]/2-$wInfo[1]/2;
			$posX=$sInfo[0]/2-$wInfo[0]/2;
			//生成混合图像
			imagecopymerge($sImage,$alpha);
			break;
		  }
	//end im加水印
	ob_start();
	imagegif($sImage);
	$content = ob_get_contents();
		  ob_end_clean();
	$frames [ ] = $content;
	   $framed [ ] = $img['frameDelay'];
   }
   $gif_maker = new GIFEncoder (
		  $frames,$framed,bin   //bin为二进制   url为地址
	 );
   $image_rs = $gif_maker->GetAnimation ( );
   //如果没有给出保存文件名,默认为原图像名
		 @unlink($source);
		 //保存图像
		 file_put_contents($source,$image_rs);
		 return true;
		}   
		//建立图像
  $sCreateFun=imagecreatefrom.$sInfo['type'];
  if(!function_exists($sCreateFun))
   $sCreateFun = 'imagecreatefromjpeg';
  $sImage=$sCreateFun($source);
		$wCreateFun=imagecreatefrom.$wInfo['type'];
  if(!function_exists($wCreateFun))
   $wCreateFun = 'imagecreatefromjpeg';
		$wImage=$wCreateFun($water);
		//设定图像的混色模式
		imagealphablending($wImage,true);
		switch (intval($position))
		{
		 case 0: break;
		 //左上
		 case 1:
		  $posY=0;
		  $posX=0;
		  //生成混合图像
		  imagecopymerge($sImage,$alpha);
		  break;
		 //右上
		 case 2:
		  $posY=0;
		  $posX=$sInfo[0]-$wInfo[0];
		  //生成混合图像
		  imagecopymerge($sImage,$alpha);
		  break;
		 //左下
		 case 3:
		  $posY=$sInfo[1]-$wInfo[1];
		  $posX=0;
		  //生成混合图像
		  imagecopymerge($sImage,$alpha);
		  break;
		 //右下
		 case 4:
		  $posY=$sInfo[1]-$wInfo[1];
		  $posX=$sInfo[0]-$wInfo[0];
		  //生成混合图像
		  imagecopymerge($sImage,$alpha);
		  break;
		 //居中
		 case 5:
		  $posY=$sInfo[1]/2-$wInfo[1]/2;
		  $posX=$sInfo[0]/2-$wInfo[0]/2;
		  //生成混合图像
		  imagecopymerge($sImage,$alpha);
		  break;
		}
		//如果没有给出保存文件名,默认为原图像名
		@unlink($source);
		//保存图像
		imagejpeg($sImage,$source,100);
		imagedestroy($sImage);
	}
}
if(!function_exists('image_type_to_extension'))
{
 function image_type_to_extension($imagetype)
 {
  if(empty($imagetype))
   return false;
  switch($imagetype)
  {
   case IMAGETYPE_GIF    : return '.gif';
   case IMAGETYPE_JPEG   : return '.jpeg';
   case IMAGETYPE_PNG    : return '.png';
   case IMAGETYPE_SWF    : return '.swf';
   case IMAGETYPE_PSD    : return '.psd';
   case IMAGETYPE_BMP    : return '.bmp';
   case IMAGETYPE_TIFF_II : return '.tiff';
   case IMAGETYPE_TIFF_MM : return '.tiff';
   case IMAGETYPE_JPC    : return '.jpc';
   case IMAGETYPE_JP2    : return '.jp2';
   case IMAGETYPE_JPX    : return '.jpf';
   case IMAGETYPE_JB2    : return '.jb2';
   case IMAGETYPE_SWC    : return '.swc';
   case IMAGETYPE_IFF    : return '.aiff';
   case IMAGETYPE_WBMP   : return '.wbmp';
   case IMAGETYPE_XBM    : return '.xbm';
   default               : return false;
  }
 }
}

/***   来自编程之家 jb51.cc(jb51.cc)   ***/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读8.4k次,点赞8次,收藏7次。SourceCodester Online Tours & Travels Management System pay.php sql injectionLine 16 of pay.php invokes a SQL query built using unvalidated input. This call could allow an attacker to modify the statement’s meaning or to execute arbitrary SQL commands.SQL
文章浏览阅读3.4k次,点赞46次,收藏51次。本文为大家介绍在windwos系统搭建typecho博客+cpolar内网穿透工具将博客发布到公共网络环境,实现远程也可以访问和操作。_windows搭建typecho
文章浏览阅读1.1k次。- php是最优秀, 最原生的模板语言, 替代语法,让php更加的优雅的与html生活在一起 -->请放心, 最终生成的,或者说用户最终看到的,仍然是一个html文档, php代码中的内容不会被泄漏的。-- 将php与html代码混编的时候,大括号很容易造成配对错误,最好杜绝它 -->php标签内部代码由php.exe解释, php标签之外的代码原样输出,仍由web服务器解析。-- 所以php的流程控制语句, 都提供了替代语法,用冒号代替大括号 -->php echo '百变鹏仔'?_利用php将静态页面修改为动态页面
文章浏览阅读1.1k次,点赞18次,收藏15次。整理K8s网络相关笔记博文内容涉及 Linux network namespace 认知以及彼此通信Demo,实际中的应用理解不足小伙伴帮忙指正不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已经和从前不一样了。——村上春树。_linux network namespace 多端通信 模式认知
文章浏览阅读1.2k次,点赞22次,收藏19次。此网络模型提供了一个逻辑二层(L2)网络,该网络封装在跨 Kubernetes 集群节点的现有三层(L3)网络拓扑上。使用此模型,可以为容器提供一个隔离的 L2 网络,而无需分发路由。封装网络带来了少量的处理开销以及由于覆盖封装生成 IP header 造成的 IP 包大小增加。封装信息由 Kubernetes worker 之间的 UDP 端口分发,交换如何访问 MAC 地址的网络控制平面信息。此类网络模型中常用的封装是 VXLAN、Internet 协议安全性 (IPSec) 和 IP-in-IP。_k8s网络组件对比
文章浏览阅读1.1k次,点赞14次,收藏19次。当我们谈论网络安全时,我们正在讨论的是保护我们的在线空间,这是我们所有人的共享责任。网络安全涉及保护我们的信息,防止被未经授权的人访问、披露、破坏或修改。
文章浏览阅读1.3w次,点赞3次,收藏7次。尽管您可以通过 ping 命令解析出网站的 IP 地址,但是可能在浏览器中访问时仍然遇到问题,这可能是因为浏览器使用的 DNS 解析结果不同于 ping 命令使用的解析结果。可能是因为您的网络或设备上设置了防火墙,阻止了对特定网站的访问。有些国家或组织可能会对特定的域名进行屏蔽,从而阻止访问相关网站。如果您的网络使用代理服务器进行访问控制,可能会由于代理服务器的配置问题导致无法访问某些网站。即使您的网络和设备一切正常,目标网站本身可能也存在问题,例如服务器故障、维护或过载,导致无法访问。_能ping通打不开网页
文章浏览阅读839次,点赞22次,收藏19次。本系统带文档lw万字以上文末可领取本课题的JAVA源码参考。
文章浏览阅读2.1k次,点赞31次,收藏22次。基于微信小程序奶茶点餐外卖系统设计与实现(PHP后台+Mysql)可行性分析毕设源代码毕业设计,数据安全和系统稳定性以及团队能力和资源配备方面都具备较好的条件。因此,该项目的可行性较高。:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;微信小程序作为一种快捷、方便的移动应用形式,成为很多用户点餐外卖的首选。项目的界面和功能都可以定制,包安装运行!项目配有对应开发文档、开题报告、任务书、PPT、论文模版等。
文章浏览阅读1.8k次,点赞52次,收藏38次。本文主要通过对系统的前台系统和后台管理系统进行了功能性需求分析,对系统的安全性和可扩展性进行了非功能性需求分析。在详细的需求分析的基础上,根据系统的功能设计确定了数据库结构,实现完整的代码编写。Lucky+Baby母婴用品网站使用 Dreamweaver、HBuilder代码编辑器、Apache服务器等开发工具,完成了系统的主要模块的页面设计和功能实现。本文展示了首页页面的实现效果图,并通过代码和页面介绍了用户注册功能、商品搜索功能、生成订单和查看我的订单功能、在线付款功能功能的实现过程。
文章浏览阅读1.5k次,点赞45次,收藏40次。本设计主要实现集人性化、高效率、便捷等优点于一身的人事信息管理系统,完成首页、系统用户、通知公告、部门信息、员工薪资、考勤签到、员工请假、招聘信息、应聘信息等功能模块。
文章浏览阅读1k次。该错误通常出现在数据库读取结果集数据时,比如当我们写好SQL语句从数据库读取数据时,本身应该返回结果集,再给结果集中读取数据。解决思路:这种错误一般是因为echo后面输出了一个数组导致的,或者是数组作为字符串进行拼接运算时导致的。该错误直译为:警告:mysqli_fetch_assoc函数期望参数1是mysqli的结果集,但是给了一个布尔值。这种错误是PHP解析器在解析时遇到了语法错误,直译为:解析错误:语法错误,意料之外的...该错误直译为:提示:未定义的索引:username。_array to string conversion in
文章浏览阅读2.7w次。解决http请求报错context deadline exceeded (Client.Timeout exceeded while awaiting headers)_context deadline exceeded (client.timeout exceeded while awaiting headers)
文章浏览阅读1.3k次,点赞26次,收藏24次。复杂网络是一种由大量相互连接的元素(节点或顶点)组成的网络结构,这些连接通常是非常复杂和动态的。这些网络可以在各种领域中发现,包括社交网络、生物学系统、信息技术和交通系统等。_代理建模
文章浏览阅读2.6k次,点赞76次,收藏71次。epoll详解,事件模型,ET/LT模式,并通过三个示例进行代码实现。
文章浏览阅读3.3k次。罗拉ROLA-IP是一家来自纽约的代理IP提供商,由李嘉诚先生投资建设,韩国人工智能、自动驾驶、虚拟现实方面的领军企业World IT Show投资入股,由美国纽约大学IT管理教授团队研究开发,进入中国市场6年多,全世界设有多个分子公司。接下来,我们要检查代理和防火墙的设置,因为在绝大多数情况下,它们是导致这个错误的原因,尤其是当用户使用免费代理时。对网站的访问受阻实际上是一个非常常见的错误,它既可能是由于物理原因(硬件问题)造成的,也可能是由于软件错误引起的。检查代理设置,并确保其正确配置。_无法访问此网站,检查代理服务器和防火墙
文章浏览阅读1.1k次,点赞14次,收藏20次。本系统带文档lw万字以上文末可领取本课题的JAVA源码参考。_php洗车服务预约管理系统php源码
文章浏览阅读1.1k次。桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。
文章浏览阅读936次,点赞22次,收藏17次。本系统带文档lw万字以上文末可领取本课题的JAVA源码参考。
文章浏览阅读822次,点赞15次,收藏14次。在整个设计过程中,要确定可能的具体解决方案,以实现每一个小的最终目标,对于每一个小目标,我们首先必须了解一些相关的需求分析信息。除了以上作品下面是2023-2024年最新100套计算机专业原创的毕业设计源码+数据库,是近期作品,如果你的题目刚好在下面可以文末领取java源码参考。springboot基于springboot的在线考试系统。springboot基于springboot的商城购物系统。springboot基于微信小程序的智慧校园设计与实现。springboot基于用户的协同过滤算法的话题推荐。