作者简介:Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师
主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互助
收藏点赞不迷路 关注作者有好处
文末获取源码
项目编号:L-BS-SP-01
一,环境介绍
语言环境:Java: jdk1.8
数据库:Mysql: mysql5.7
应用服务器:Tomcat: tomcat8.5.31
开发工具:IDEA或eclipse
二,项目简介
2.1 技术介绍
- 前端采用Vue、Element UI、nuxt
- 基础平台采用的是RuoYi-Vue
- 后端采用Spring Boot、Spring Security、Redis & Jwt。
- 权限认证使用Jwt,支持多终端认证系统。
- 支持加载动态权限菜单,多方式轻松权限控制。
- 高效率开发,使用代码生成器可以一键生成前后端代码。
- vue-simple-uploader:一款基于 simple-uploader.js 开发的适用于 Vue.js 的分片上传插件
- vue-video-player:一款基于 video.js 开发的视频播放组件
- 集成了奇文网盘qiwen-file
- 后台管理系统模块增加了资源管理模块、媒资管理模块、站点配置模块、博客模块、问答模块
- 集成plumelog日志,计划去除原sysLog日志。日志统一在plumelog上查看
2.2 项目介绍
该平台是一款基于RuoYi-Vue前后端分离基础平台打造的开源电影视频平台。该平台集成了奇文网盘,涵盖了电影、博客、问答等多个模块,致力于为用户提供丰富多样的视频内容以及互动交流的社区体验。后台和门户均采用了Vue+SpringBoot技术栈,保证了系统的高效稳定运行。
功能描述:
一、用户端功能
- 首页:展示最新上映的电影、热门电影推荐、精彩博文、热门问答等内容,为用户提供一站式浏览体验。
- 电影:提供电影详情页,包括电影简介、演员表、剧照、相关推荐等信息,支持在线观看和下载。
- 演员:展示演员个人资料、参演作品、获奖记录等信息,方便用户了解关注的演员动态。
- 文章:允许用户发表和浏览博客文章,分享观影心得、影评、行业动态等内容。
- 问答:提供一个互动问答社区,用户可以提问、回答问题,分享知识和经验。
- 热门:展示平台上的热门电影、文章、问答等内容,方便用户了解平台上的热门话题和趋势。
- 登录与注册:支持用户注册和登录功能,保护用户个人信息和观影记录。
- 搜索:提供全站搜索功能,方便用户快速找到感兴趣的电影、文章或问答。
二、后台管理系统模块
- 资源管理模块:负责管理平台上的电影资源,包括电影的上传、编辑、删除等功能,确保电影资源的准确性和实时性。
- 媒资管理模块:负责管理平台上的视频资源,包括视频的上传、编辑、审核等功能,确保视频内容的质量和合规性。
- 站点配置模块:允许管理员配置站点信息,如站点名称、域名、主题、样式等,实现平台的个性化定制。
- 博客模块:支持管理员对博客文章进行管理,包括文章的审核、编辑、删除等功能,维护平台内容的质量和价值。
- 问答模块:允许管理员对问答内容进行管理,包括问题的审核、回答、删除等操作,保证问答社区的健康和活跃度。
三,系统展示
3.1 门户截图
3.2 后台截图
四,核心代码展示
4.1 演员Service业务层处理
/**
* 演员Service业务层处理
*/
@Service
public class ActorServiceImpl extends ServiceImpl<ActorMapper, Actor> implements IActorService {
@Autowired
private ActorMapper actorMapper;
/**
* 查询演员列表
*
* @param actor 演员
* @return 演员
*/
@Override
public List<Actor> selectActorList(Actor actor) {
return actorMapper.selectActorList(actor);
}
/**
* 查询热门演员
*
* @param top
* @return
*/
@Override
public List<Actor> selectHotActorList(int top) {
return actorMapper.selectHotActorList(top);
}
@Override
public List<Actor> selectNotSelectedList(Actor actor, Long[] ids) {
return actorMapper.selectNotSelectedListByIds(actor, ids);
}
}
4.2 电影Service业务层处理
/**
* 电影Service业务层处理
*/
@Service
public class MovieServiceImpl extends ServiceImpl<MovieMapper, Movie> implements IMovieService {
@Autowired
private MovieMapper movieMapper;
@Autowired
private VideoMapper videoMapper;
@Autowired
private IVideoService videoService;
@Autowired
private SysUserMapper sysUserMapper;
@Autowired
private MovieActorMapper movieActorMapper;
@Autowired
private TokenUtil tokenUtil;
@Autowired
private IWebConfigService webConfigService;
@Autowired
JustAuthConfig justAuthConfig;
/**
* 查询电影
*
* @param movieId 电影ID
* @return 电影
*/
@Override
public MovieVO selectMovieById(Long movieId) {
Movie movie = movieMapper.selectById(movieId);
MovieVO movieVO = new MovieVO();
if (movie != null) {
BeanUtils.copyProperties(movie, movieVO);
String publishBy = movieVO.getPublishBy();
if (StringUtils.isNotEmpty(publishBy)) {
SysUser sysUser = sysUserMapper.selectUserById(Long.valueOf(publishBy));
movieVO.setPublishUsername(sysUser != null ? sysUser.getNickName() : null);
}
movieVO.setVideoList(videoService.selectVideoByMovieId(movieId));
//查询演员和导演信息
MovieActorVO movieActorQuery = new MovieActorVO();
movieActorQuery.setMovieId(movieVO.getMovieId());
movieActorQuery.setType(MovieActorType.ACTOR.getValue());
List<MovieActorVO> actorList = movieActorMapper.selectMovieActorList(movieActorQuery);
movieActorQuery.setType(MovieActorType.DIRECTOR.getValue());
List<MovieActorVO> directorList = movieActorMapper.selectMovieActorList(movieActorQuery);
movieVO.setDirectorList(directorList);
movieVO.setActorList(actorList);
}
return movieVO;
}
@Override
public MovieVO selectWebMovieById(Long movieId) {
MovieVO movieVO = movieMapper.selectWebMovieById(movieId);
movieVO.setVideoList(videoService.selectVideoByMovieId(movieId));
return movieVO;
}
/**
* 查询电影列表
*
* @param movie 电影
* @return 电影
*/
@Override
public List<MovieVO> selectMovieList(Movie movie) {
return movieMapper.selectMovieList(movie);
}
/**
* 新增电影
*
* @param movieVO 电影
* @return 结果
*/
@Transactional
@Override
public int insertMovie(MovieVO movieVO) {
// 初始化数据
this.initData(movieVO);
int rows = movieMapper.insert(movieVO);
if (rows > 0) {
this.insertVideo(movieVO);
this.insertActor(movieVO, MovieActorType.ACTOR);
this.insertActor(movieVO, MovieActorType.DIRECTOR);
String url = "movie/" + movieVO.getMovieId();
String qrcodePath = generateQr(url);
movieVO.setQrcodePath(qrcodePath);
movieMapper.updateById(movieVO);
}
return rows;
}
/**
* 初始化数据
*
* @param movieVO
*/
private void initData(MovieVO movieVO) {
String title = movieVO.getTitle();
if (StringUtils.isNotBlank(title)) {
String en = PinyinUtil.getPinyin(title, "");
String letter = PinyinUtil.getFirstLetter(title, "");
movieVO.setEn(en);
movieVO.setLetter(letter.toUpperCase());
}
// 设置视频总长度
List<Video> videoList = movieVO.getVideoList();
if (videoList == null || videoList.size() == 0) {
return;
}
long totalVideoLength = 0;
for (Video video : videoList) {
String length = video.getLength();
if (StringUtils.isNotEmpty(length)) {
totalVideoLength += Long.valueOf(length);
}
}
movieVO.setTotalVideoLength(totalVideoLength);
}
/**
* @param movieVO
* @Desc 更新演员
*/
private void insertActor(MovieVO movieVO, MovieActorType movieActorType) {
Long movieId = movieVO.getMovieId();
List<MovieActorVO> actorList = movieVO.getActorList();
List<MovieActorVO> directorList = movieVO.getDirectorList();
List<MovieActorVO> insertList = null;
switch (movieActorType) {
case ACTOR:
insertList = actorList;
break;
case DIRECTOR:
insertList = directorList;
break;
default:
return;
}
if (StringUtils.isNotNull(insertList)) {
for (MovieActorVO movieActorVO : insertList) {
MovieActor movieActor = new MovieActor();
BeanUtils.copyProperties(movieActorVO, movieActor);
movieActor.setMovieId(movieId);
movieActor.setType(movieActorType.getValue());
movieActorMapper.insertMovieActor(movieActor);
}
}
}
/**
* 修改电影
*
* @param movieVO 电影
* @return 结果
*/
@Transactional
@Override
public int updateMovie(MovieVO movieVO) {
videoMapper.deleteByMovieId(movieVO.getMovieId());
// 初始化数据
this.initData(movieVO);
this.insertVideo(movieVO);
Map movieActorMap = new HashMap<>();
movieActorMap.put("movie_id", movieVO.getMovieId());
movieActorMapper.deleteByMap(movieActorMap);
this.insertActor(movieVO, MovieActorType.ACTOR);
this.insertActor(movieVO, MovieActorType.DIRECTOR);
if (StringUtils.isBlank(movieVO.getQrcodePath())) {
String url = "movie/" + movieVO.getMovieId();
String qrcodePath = generateQr(url);
movieVO.setQrcodePath(qrcodePath);
}
return movieMapper.updateById(movieVO);
}
/**
* 删除电影信息
*
* @param movieId 电影ID
* @return 结果
*/
@Override
@Transactional
public int deleteMovieById(Long movieId) {
videoMapper.deleteByMovieId(movieId);
return movieMapper.deleteById(movieId);
}
@Override
public List<MovieVO> selectHotMovieList(int top) {
return movieMapper.selectHotMovieList(top);
}
@Override
public int removeActorList(Long[] actorIds) {
return movieActorMapper.deleteMovieActorByIds(actorIds);
}
@Override
public List<MovieVO> getListByActorId(Long actorId) {
return movieMapper.selectListByActorId(actorId);
}
@Override
public List<Movie> getSameTypeMovieList(Long movieId) {
MovieVO movieVO = this.selectMovieById(movieId);
Integer categoryId = movieVO.getCategoryId();
Page<Movie> page = new Page<>(1, 12);
QueryWrapper<Movie> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("status", 0);
queryWrapper.eq("category_id", categoryId);
queryWrapper.notIn("movie_id", movieId);
queryWrapper.select("movie_id", "images", "title", "type", "country", "tag_id", "publish_by", "publish_time", "open_comment", "rate", "category_id", "category_name");
queryWrapper.orderByDesc("create_time");
return movieMapper.selectPage(page, queryWrapper).getRecords();
}
/**
* 新增电影视频信息
*
* @param movieVO 电影对象
*/
public void insertVideo(MovieVO movieVO) {
List<Video> videoList = movieVO.getVideoList();
Long movieId = movieVO.getMovieId();
if (StringUtils.isNotNull(videoList)) {
List<Video> list = new ArrayList<Video>();
for (Video video : videoList) {
video.setMovieId(movieId);
list.add(video);
}
if (list.size() > 0) {
videoMapper.batchVideo(list);
}
}
}
@Override
public List<MovieVO> selectWebMovieList(MovieVO movieVO) {
return movieMapper.selectWebMovieList(movieVO);
}
@Override
public List<MovieVO> search(SearchParamVO searchParamVO) {
List<MovieVO> movieVOList = movieMapper.searchWebMovieList(searchParamVO);
String keyword = searchParamVO.getKeyword();
movieVOList.forEach(item -> {
// 给标题、简介、分类 设置高亮
item.setTitle(getHitCode(item.getTitle(), keyword));
item.setDescription(getHitCode(item.getDescription(), keyword));
item.setCategoryName(getHitCode(item.getCategoryName(), keyword));
});
return movieVOList;
}
/**
* 添加高亮
*
* @param str 截取字符串
* @param keyword 关键字
* @return 返回添加了高亮的字符串
*/
private String getHitCode(String str, String keyword) {
if (StringUtils.isAnyBlank(str, keyword)) {
return "";
}
String startStr = "<span style = 'color:red'>";
String endStr = "</span>";
// 判断关键字是否直接是搜索的内容,否者直接返回
if (str.equalsIgnoreCase(keyword)) {
return startStr + str + endStr;
}
String lowerCaseStr = str.toLowerCase();
String lowerKeyword = keyword.toLowerCase();
String[] lowerCaseArray = lowerCaseStr.split(lowerKeyword);
boolean isEndWith = lowerCaseStr.endsWith(lowerKeyword);
// 计算分割后的字符串位置
int count = 0;
List<Map<String, Integer>> list = new ArrayList<>();
List<Map<String, Integer>> keyList = new ArrayList<>();
for (int index = 0; index < lowerCaseArray.length; index++) {
// 将切割出来的存储map
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> keyMap = new HashMap<>();
map.put("startIndex", count);
int len = lowerCaseArray[index].length();
count += len;
map.put("endIndex", count);
list.add(map);
if (index < lowerCaseArray.length - 1 || isEndWith) {
// 将keyword存储map
keyMap.put("startIndex", count);
count += keyword.length();
keyMap.put("endIndex", count);
keyList.add(keyMap);
}
}
// 截取切割对象
List<String> arrayList = new ArrayList<>();
for (Map<String, Integer> item : list) {
Integer start = item.get("startIndex");
Integer end = item.get("endIndex");
String itemStr = str.substring(start, end);
arrayList.add(itemStr);
}
// 截取关键字
List<String> keyArrayList = new ArrayList<>();
for (Map<String, Integer> item : keyList) {
Integer start = item.get("startIndex");
Integer end = item.get("endIndex");
String itemStr = str.substring(start, end);
keyArrayList.add(itemStr);
}
StringBuilder sb = new StringBuilder();
for (int index = 0; index < arrayList.size(); index++) {
sb.append(arrayList.get(index));
if (index < arrayList.size() - 1 || isEndWith) {
sb.append(startStr);
sb.append(keyArrayList.get(index));
sb.append(endStr);
}
}
return sb.toString();
}
/**
* 生成二维码
*
* @param url
* @return
*/
private String generateQr(String url) {
String profile = RuoYiConfig.getProfile();
WebConfig webConfig = webConfigService.getWebConfig();
String logoURL = webConfig.getLogo();
String logoPath = profile + logoURL;
QrConfig qrConfig = QrConfig.create()
.setWidth(300)
.setHeight(300);
File logoFile = new File(logoPath);
if (logoFile.exists()) {
qrConfig.setImg(logoFile);
}
String qrRootPath = RuoYiConfig.getQrPath();
String websiteUrl = justAuthConfig.getWebsiteUrl();
String fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID().replace("-", "") + ".jpg";
String realQrPath = qrRootPath + File.separator + fileName;
File realQrFile = new File(realQrPath);
if (!realQrFile.exists()) {
if (!realQrFile.getParentFile().exists()) {
realQrFile.getParentFile().mkdirs();
}
}
File file = QrCodeUtil.generate(websiteUrl + url, qrConfig, FileUtil.file(realQrFile));
int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
String currentDir = StringUtils.substring(qrRootPath, dirLastIndex);
if (file.exists()) {
return "/" + currentDir + "/" + fileName;
} else {
return "";
}
}
}
五,相关作品展示
基于Java开发、Python开发、PHP开发、C#开发等相关语言开发的实战项目
基于Nodejs、Vue等前端技术开发的前端实战项目
基于微信小程序和安卓APP应用开发的相关作品
基于51单片机等嵌入式物联网开发应用
基于各类算法实现的AI智能应用
基于大数据实现的各类数据管理和推荐系统