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 blocke.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,填充方式为PKCS5Paddingprivate 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->indexthis.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 方式二

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1552736.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

分支和循环(1)

目录 前言 1.什么是语句&#xff1f; 2.分支语句&#xff08;选择语句&#xff09; 2.1 if 语句 2.2if书写格式形式的对比 2.3 if 练习 2.4 switch 语句 2.5 switch 练习 总结 前言 分支合循环首先就是要有良好的代码风格&#xff0c;缩进得当&#xff0c;要不然真的很…

横排文字、图层蒙版-1(2024年09月30日)

2024年09月30日 记录_导读 2024年09月30日 10:13 关键词 优惠券 设计 图层 背景 元素 调整 画笔工具 颜色 大小 位置 复制 移动 添加涂层 多选 显示 PS 元素文件 隐藏 使用规则 Logo 全文摘要 通过在Photoshop中精心操作图层&#xff0c;包括复制、移动和调整设置&#xf…

结构型模式-适配器-桥接-外观-代理

适配器模式 是什么 将一个类的接口转换成客户希望的另外一个接口 解决接口不兼容问题,复用之前的代码 实例 public class PoliceCarAdapter extends CarController { private PoliceSound sound;//定义适配者PoliceSound对象 private PoliceLamp lamp;//定义适配者Polic…

虚拟机U盘启动

二、注意事项 1、正确顺序是先插入U盘启动盘&#xff0c;再打开虚拟机&#xff0c;否则虚拟机无法检测到U盘&#xff1b; 2、如果已经打开虚拟机&#xff0c;则需关闭&#xff0c;插入U盘后重新开启。 3、设置好后如果换另一个U盘进行U盘启动&#xff0c;以下步骤要重新再设置&…

Python核心知识:pip使用方法大全

什么是 pip&#xff1f; pip 是 Python 的包管理工具&#xff0c;允许用户安装、升级和管理 Python 的第三方库和依赖。它极大地简化了开发过程&#xff0c;使开发者可以轻松地获取并安装所需的软件包。pip 已成为 Python 项目中最常见的包管理工具&#xff0c;并且自 Python …

windows C++-UWP 应用中使用 HttpRequest 类

在 UWP 应用中使用 HttpRequest 类 本节演示在 UWP 应用中如何使用 HttpRequest 类。 应用程序会提供一个输入框&#xff0c;该输入框定义了一个 URL 资源、用于执行 GET 和 POST 操作的按钮命令和用于取消当前操作的按钮命令。 使用 HttpRequest 类 1. 在 MainPage.xaml 中…

8639 折半插入排序

### 思路 折半插入排序是一种改进的插入排序算法&#xff0c;通过二分查找来确定插入位置&#xff0c;从而减少比较次数。每次插入时&#xff0c;先用二分查找找到插入位置&#xff0c;然后将元素插入到正确的位置。 ### 伪代码 1. 读取输入的待排序关键字个数n。 2. 读取n个待…

class 030 异或运算的骚操作

这篇文章是看了“左程云”老师在b站上的讲解之后写的, 自己感觉已经能理解了, 所以就将整个过程写下来了。 这个是“左程云”老师个人空间的b站的链接, 数据结构与算法讲的很好很好, 希望大家可以多多支持左程云老师, 真心推荐. https://space.bilibili.com/8888480?spm_id_f…

【CKA】五、网络策略–NetworkPolicy

5、配置网络策略–NetworkPolicy 1. 考题内容&#xff1a; 2. 答题思路&#xff1a; 1、根据题目分析要创建怎样的网络策略 2、按题目要求查看ns corp-net的label 3、编写yaml&#xff0c;其中注意 namespace、label、port 3. 官网地址&#xff1a; https://kubernetes.io/…

解决connect因父类不明确而报错的问题

如图所示&#xff0c;connect函数报错&#xff0c;原因是connect的检查是在编译期完成的&#xff0c;而传入父类则是在运行时&#xff0c;从而引起connect不知道parent是谁而报错。只需加入类型转换即可。 connect(qobject_cast<TableWidget*>(parent), &TableWidg…

STM32F1+HAL库+FreeTOTS学习15——互斥信号量

STM32F1HAL库FreeTOTS学习15——互斥信号量 1. 优先级翻转2. 互斥信号量3. 相关API函数&#xff1b;3.1 互斥信号量创建3.2 获取信号量3.3 释放信号量3.4 删除信号量 4. 操作实验1. 实验内容2. 代码实现3. 运行结果 上期我们介绍了数值信号量。这一期我们来介绍互斥信号量 1. 优…

【计算机毕业设计】springboot企业客户信息反馈平台

摘 要 网络的广泛应用给生活带来了十分的便利。所以把企业客户信息反馈管理与现在网络相结合&#xff0c;利用java技术建设企业客户信息反馈平台&#xff0c;实现企业客户信息反馈的信息化。则对于进一步提高企业客户信息反馈管理发展&#xff0c;丰富企业客户信息反馈管理经验…

官网:视觉是第一记忆,没有记忆点的官网设计是失败的。

官方网站虽然不像之前那么火爆了&#xff0c;但是依然是企业展示品牌形象和吸引用户的重要渠道。仅仅拥有一个官方网站并不足以吸引用户&#xff0c;更重要的是网站的设计是否能够给用户留下深刻的记忆。 当前&#xff0c;用户对于网站的要求也越来越高&#xff0c;他们不仅仅希…

Arduino UNO R3自学笔记16 之 Arduino的定时器介绍及应用

注意&#xff1a;学习和写作过程中&#xff0c;部分资料搜集于互联网&#xff0c;如有侵权请联系删除。 前言&#xff1a;学习定时器的功能。 1.定时器介绍 定时器也是一种中断&#xff0c;属于软件中断。 它就像一个时钟&#xff0c;可以测量事件的时间间隔。 比如早…

重置linux后vscode无法再次使用ssh连接

如果你使用过vscode ssh远程连接了一个Linux系统&#xff0c;但该系统被重置了&#xff0c;并且关键配置没有改变。再次使用vscode连接时&#xff0c;vscode可能无法连接。 原因&#xff1a;vscode远程连接后会在C:\Users{{你的用户名}}.ssh下的known_hosts和known_hosts.old。…

停止模式下USART为什么可以唤醒MCU?

在MCU的停止模式下&#xff0c;USART之类的外设时钟是关闭的&#xff0c;但是USART章节有描述到在停止模式下可以用USART来对MCU进行唤醒&#xff1a; 大家是否会好奇在外设的时钟被关闭的情况下&#xff0c;USART怎么能通过接收中断或者唤醒事件对MCU进行唤醒的呢&#xff1…

2024多模态大模型发展调研

随着生成式大语言模型应用的日益广泛&#xff0c;其输入输出模态受限的问题日益凸显&#xff0c;成为制约技术进一步发展的瓶颈。为突破这一局限&#xff0c;本文聚焦于研究多模态信息的协同交互策略&#xff0c;旨在探索一种能够统一理解与生成的多模态模型构建方法。在此基础…

基于springboot+小程序的在线选课管理系统1(源码+sql脚本+视频导入教程+文档)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于springboot小程序的在线选课管理系统实现了管理员、教师及学生。 1、管理员实现了首页、个人中心、管理员管理、教师管理、学生管理、课程信息管理、选课信息、公告管理、论坛管理、基…

Redis哨兵模式的搭建以及配置参数简介

原理 Redis哨兵模式是一种用于在Redis主从复制环境中进行高可用性监控和故障恢复的机制。该模式引入了一个或多个哨兵节点&#xff0c;这些节点负责监控Redis服务器的状态&#xff0c;并在主节点发生故障时切换为新的主节点。 哨兵节点的工作原理如下&#xff1a; 1、哨兵节点…

PDF阅读器工具集萃:满足你的多样需求

现在阅读书籍大部分都喜欢电子书的形式了吧&#xff0c;因为小小的一个设备就能存下上万本书。从流传程度来说PDF无疑是一个使用最广的格式。除了福昕PDF阅读器阅读之外还有哪些好用的阅读工具呢/&#xff1f;今天我们一起来探讨一下吧。 1.福昕阅读器 链接一下>>www.f…