DC00025【含论文】基于协同过滤推荐算法springboot视频推荐管理系统

1、项目功能演示

DC00025【含文档】基于springboot短视频推荐管理系统协同过滤算法视频推荐系统javaweb开发程序设计vue

2、项目功能描述

短视频推荐系统分为用户和系统管理员两个角色

2.1 用户角色

1、用户登录、用户注册
2、视频中心:信息查看、视频收藏、点赞、踩、评论
3、公告信息:信息查看、收藏、点赞
4、个人信息、修改密码、我的收藏

2.2 管理员角色

1、系统登录
2、个人中心:修改密码、个人信息修改
3、用户管理
4、视频中心管理
5、视频分类管理
6、系统管理:轮播图管理、公告管理、公告信息分类管理

3、项目运行截图

 

4、项目核心代码

4.1  公共处理类

package com.utils;

import java.util.Random;
import java.util.ArrayList;
import org.springframework.stereotype.Component;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import org.apache.poi.ss.usermodel.DateUtil;
import java.util.Objects;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;

@Component
public class CommonUtil {
	/**
     * 获取随机字符串
     *
     * @param num
     * @return
     */
    public static String getRandomString(Integer num) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < num; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

	/**
	 * 获取随机验证码
	 *
	 * @param num
	 * @return
	 */
	public static String getRandomNumber(Integer num) {
	    String base = "0123456789";
	    Random random = new Random();
	    StringBuffer sb = new StringBuffer();
	    for (int i = 0; i < num; i++) {
	        int number = random.nextInt(base.length());
	        sb.append(base.charAt(number));
	    }
	    return sb.toString();
	}

    public static String getCellValue(Cell cell) {
        String resultValue = "";
        // 判空
        if (Objects.isNull(cell)) {
            return resultValue;
        }

        // 拿到单元格类型
        int cellType = cell.getCellType();
        switch (cellType) {
            // 字符串类型
            case Cell.CELL_TYPE_STRING:
                resultValue = StringUtils.isEmpty(cell.getStringCellValue()) ? "" : cell.getStringCellValue().trim();
                break;
            // 布尔类型
            case Cell.CELL_TYPE_BOOLEAN:
                resultValue = String.valueOf(cell.getBooleanCellValue());
                break;
            // 数值类型
            case Cell.CELL_TYPE_NUMERIC:
                /**
                 * format 的值可能为以下这些 yyyyMMddHHmmss
                 * yyyy-MM-dd----- 14
                 * yyyy年m月d日----- 31
                 * yyyy年m月--------57
                 * m月d日  -----------58
                 * HH:mm-----------20
                 * h时mm分  --------- 32
                 */
                Object val = cell.getNumericCellValue();
                // POI Excel 日期格式转换
                String formatDate = "";
                switch (cell.getCellStyle().getDataFormat()){
                    case 14:
                        formatDate = "yyyy-MM-dd";
                        break;
                    case 20:
                        formatDate = "HH:mm";
                        break;
                    case 21:
                        formatDate = "HH:mm:ss";
                        break;
                    case 31:
                        formatDate = "yyyy年MM月dd日";
                        break;
                    case 32:
                        formatDate = "HH时mm分";
                        break;
                    case 33:
                        formatDate = "HH时mm分mm秒";
                        break;
                    case 57:
                        formatDate = "yyyy年MM月";
                        break;
                    case 58:
                        formatDate = "MM月dd日";
                        break;
                    case 176:
                        formatDate = "yyyy-MM-dd HH:mm:ss";
                        break;
                }
                if(!"".equals(formatDate)){
                    resultValue = new SimpleDateFormat(formatDate).format(DateUtil.getJavaDate((Double) val));
                }else{
                    resultValue = new DecimalFormat("#.######").format(cell.getNumericCellValue());
                }
                break;
            // 取空串
            default:
                break;
        }
        return resultValue;
    }





}

4.2 加密解密处理类

package com.utils;

import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import cn.hutool.crypto.digest.DigestUtil;

public class EncryptUtil {
    
	/**
	 * md5算法
	 * @param text明文
	 * @param key密钥
	 * @return 密文
	 */
	// 带秘钥加密
	public static String md5(String text) {
        if(text==null) return null;
		// 加密后的字符串
		String md5str = DigestUtil.md5Hex(text);
		return md5str;
	}
	
	/**
	 * SHA-256算法
	 * @param text
	 * @return
	 * @throws Exception
	 */
    public static String sha256(String text) {
        if(text==null) return null;
    	StringBuilder stringBuilder = new StringBuilder();
        try {
			//获取SHA-256算法实例
			MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
			//计算散列值
			byte[] digest = messageDigest.digest(text.getBytes());
			//将byte数组转换为15进制字符串
			for (byte b : digest) {
			    stringBuilder.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
			}
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return stringBuilder.toString();
    }
    
    private static final String DES_ALGORITHM = "DES";

    /**
     * DES加密
     *
     * @param data 待加密的数据
     * @param key  密钥,长度必须为8位
     * @return 加密后的数据,使用Base64编码
     */
    public static String desEncrypt(String text) {
        if(text==null) return null;
        try {
            String key = "12345678";
			// 根据密钥生成密钥规范
			KeySpec keySpec = new DESKeySpec(key.getBytes());
			// 根据密钥规范生成密钥工厂
			SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
			// 根据密钥工厂和密钥规范生成密钥
			SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);

			// 根据加密算法获取加密器
			Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
			// 初始化加密器,设置加密模式和密钥
			cipher.init(Cipher.ENCRYPT_MODE, secretKey);
			// 加密数据
			byte[] encryptedData = cipher.doFinal(text.getBytes());
			// 对加密后的数据进行Base64编码
			return Base64.getEncoder().encodeToString(encryptedData);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
        return null;
    }

    /**
     * DES解密
     *
     * @param encryptedData 加密后的数据,使用Base64编码
     * @param key 密钥,长度必须为8位
     * @return 解密后的数据
     */
    public static String desDecrypt(String text) {
        if(text==null) return null;
        try {
            String key = "12345678";
			// 根据密钥生成密钥规范
			KeySpec keySpec = new DESKeySpec(key.getBytes());
			// 根据密钥规范生成密钥工厂
			SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
			// 根据密钥工厂和密钥规范生成密钥
			SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);

			// 对加密后的数据进行Base64解码
			byte[] decodedData = Base64.getDecoder().decode(text);
			// 根据加密算法获取解密器
			Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
			// 初始化解密器,设置解密模式和密钥
			cipher.init(Cipher.DECRYPT_MODE, secretKey);
			// 解密数据
			byte[] decryptedData = cipher.doFinal(decodedData);
			// 将解密后的数据转换为字符串
			return new String(decryptedData);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
        return null;
    }
    
    private static final String AES_ALGORITHM = "AES";
    // AES加密模式为CBC,填充方式为PKCS5Padding
    private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
    // AES密钥为16位
    private static final String AES_KEY = "1234567890123456";
    // AES初始化向量为16位
    private static final String AES_IV = "abcdefghijklmnop";

    /**
     * AES加密
     *
     * @param data 待加密的数据
     * @return 加密后的数据,使用Base64编码
     */
    public static String aesEncrypt(String text) {
        if(text==null) return null;
        try {
			// 将AES密钥转换为SecretKeySpec对象
			SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
			// 将AES初始化向量转换为IvParameterSpec对象
			IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
			// 根据加密算法获取加密器
			Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
			// 初始化加密器,设置加密模式、密钥和初始化向量
			cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
			// 加密数据
			byte[] encryptedData = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
			// 对加密后的数据使用Base64编码
			return Base64.getEncoder().encodeToString(encryptedData);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
        return null;
    }

    /**
     * AES解密
     *
     * @param encryptedData 加密后的数据,使用Base64编码
     * @return 解密后的数据
     */
    public static String aesDecrypt(String text) {
        if(text==null) return null;
        try {
			// 将AES密钥转换为SecretKeySpec对象
			SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
			// 将AES初始化向量转换为IvParameterSpec对象
			IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
			// 根据加密算法获取解密器
			Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
			// 初始化解密器,设置解密模式、密钥和初始化向量
			cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
			// 对加密后的数据使用Base64解码
			byte[] decodedData = Base64.getDecoder().decode(text);
			// 解密数据
			byte[] decryptedData = cipher.doFinal(decodedData);
			// 返回解密后的数据
			return new String(decryptedData, StandardCharsets.UTF_8);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
        return null;
    }

}

4.3 基于用户的协同过滤算法

package com.utils;

/**
* 类说明 : 基于用户的协同过滤算法
*/

import java.util.*;
import java.util.stream.Collectors;

public class UserBasedCollaborativeFiltering {
	
    private Map<String, Map<String, Double>> userRatings;
    private Map<String, List<String>> itemUsers;
    private Map<String, Integer> userIndex;
    private Map<Integer, String> indexUser;
    private Long[][] sparseMatrix;

    public UserBasedCollaborativeFiltering(Map<String, Map<String, Double>> userRatings) {
        this.userRatings = userRatings;
        this.itemUsers = new HashMap<>();
        
        this.userIndex = new HashMap<>();//辅助存储每一个用户的用户索引index映射:user->index
        this.indexUser = new HashMap<>();//辅助存储每一个索引index对应的用户映射:index->user

        // 构建物品-用户倒排表
        int keyIndex = 0;
        for (String user : userRatings.keySet()) {
            Map<String, Double> ratings = userRatings.get(user);
            for (String item : ratings.keySet()) {
                if (!itemUsers.containsKey(item)) {
                    itemUsers.put(item, new ArrayList<>());
                }
                itemUsers.get(item).add(user);
            }
          //用户ID与稀疏矩阵建立对应关系
            this.userIndex.put(user,keyIndex);
            this.indexUser.put(keyIndex,user);
            keyIndex++;
        }
        
        int N = userRatings.size();
        this.sparseMatrix=new Long[N][N];//建立用户稀疏矩阵,用于用户相似度计算【相似度矩阵】
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++)
            	this.sparseMatrix[i][j]=(long)0;
        }
        for(String item : itemUsers.keySet()) {
        	List<String> userList = itemUsers.get(item);
        	for(String u1 : userList) {
        		for(String u2 : userList) {
        			if(u1.equals(u2)){
                        continue;
                    }
        			this.sparseMatrix[this.userIndex.get(u1)][this.userIndex.get(u2)]+=1;
        		}
        	}
        }
        
    }

    public double calculateSimilarity(String user1, String user2) {
        //计算用户之间的相似度【余弦相似性】
        Integer id1 = this.userIndex.get(user1);
        Integer id2 = this.userIndex.get(user2);
        if(id1==null || id2==null) return 0.0;
        return this.sparseMatrix[id1][id2]/Math.sqrt(userRatings.get(indexUser.get(id1)).size()*userRatings.get(indexUser.get(id2)).size());
    }

    public List<String> recommendItems(String targetUser, int numRecommendations) {
        // 计算目标用户与其他用户的相似度
        Map<String, Double> userSimilarities = new HashMap<>();
        for (String user : userRatings.keySet()) {
            if (!user.equals(targetUser)) {
                double similarity = calculateSimilarity(targetUser, user);
                userSimilarities.put(user, similarity);
            }
        }

        // 根据相似度进行排序
        List<Map.Entry<String, Double>> sortedSimilarities = new ArrayList<>(userSimilarities.entrySet());
        sortedSimilarities.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));

        // 选择相似度最高的K个用户
        List<String> similarUsers = new ArrayList<>();
        for (int i = 0; i < numRecommendations; i++) {
            if (i < sortedSimilarities.size()) {
                similarUsers.add(sortedSimilarities.get(i).getKey());
            } else {
                break;
            }
        }

        // 获取相似用户喜欢的物品,并进行推荐
        Map<String, Double> recommendations = new HashMap<>();
        for (String user : similarUsers) {
            Map<String, Double> ratings = userRatings.get(user);
            for (String item : ratings.keySet()) {
                if (userRatings.get(targetUser)!=null && !userRatings.get(targetUser).containsKey(item)) {
                    recommendations.put(item, ratings.get(item));
                }
            }
        }

        // 排序推荐物品
        LinkedHashMap<String, Double> sortedRecommendations = new LinkedHashMap<>(recommendations);
        // 取前N个推荐物品
        int numItems = Math.min(numRecommendations, sortedRecommendations.size());
        sortedRecommendations = sortedRecommendations.entrySet()
        .stream()
        .sorted((Map.Entry.<String, Double>comparingByValue().reversed())).limit(numItems)
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
        List<String> result = new ArrayList<String>();
        result.addAll(sortedRecommendations.keySet());
        return result;
    }
    
    
}


4.4 SQL过滤


package com.utils;

import org.apache.commons.lang3.StringUtils;

import com.entity.EIException;

/**
 * SQL过滤
 */
public class SQLFilter {

    /**
     * SQL注入过滤
     * @param str  待验证的字符串
     */
    public static String sqlInject(String str){
        if(StringUtils.isBlank(str)){
            return null;
        }
        //去掉'|"|;|\字符
        str = StringUtils.replace(str, "'", "");
        str = StringUtils.replace(str, "\"", "");
        str = StringUtils.replace(str, ";", "");
        str = StringUtils.replace(str, "\\", "");

        //转换成小写
        str = str.toLowerCase();

        //非法字符
        String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};

        //判断是否包含非法字符
        for(String keyword : keywords){
            if(str.indexOf(keyword) != -1){
                throw new EIException("包含非法字符");
            }
        }

        return str;
    }
}

4.5 分页工具类


package com.utils;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.plugins.Page;

/**
 * 分页工具类
 */
public class PageUtils implements Serializable {
	private static final long serialVersionUID = 1L;
	//总记录数
	private long total;
	//每页记录数
	private int pageSize;
	//总页数
	private long totalPage;
	//当前页数
	private int currPage;
	//列表数据
	private List<?> list;
	
	/**
	 * 分页
	 * @param list        列表数据
	 * @param totalCount  总记录数
	 * @param pageSize    每页记录数
	 * @param currPage    当前页数
	 */
	public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
		this.list = list;
		this.total = totalCount;
		this.pageSize = pageSize;
		this.currPage = currPage;
		this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
	}

	/**
	 * 分页
	 */
	public PageUtils(Page<?> page) {
		this.list = page.getRecords();
		this.total = page.getTotal();
		this.pageSize = page.getSize();
		this.currPage = page.getCurrent();
		this.totalPage = page.getPages();
	}
	
	/*
	 * 空数据的分页
	 */
	public PageUtils(Map<String, Object> params) {
 		Page page =new Query(params).getPage();
		new PageUtils(page);
	}

	 
	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getCurrPage() {
		return currPage;
	}

	public void setCurrPage(int currPage) {
		this.currPage = currPage;
	}

	public List<?> getList() {
		return list;
	}

	public void setList(List<?> list) {
		this.list = list;
	}

	public long getTotalPage() {
		return totalPage;
	}

	public void setTotalPage(long totalPage) {
		this.totalPage = totalPage;
	}

	public long getTotal() {
		return total;
	}

	public void setTotal(long total) {
		this.total = total;
	}
	
}

5、项目包含

6、项目获取

6.1 方式一

 私聊或者扫描下方名片获取项目文件。

6.2 方式二

点击此处直接获取项目文件。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一棵猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值