音乐管理系统 SpringBoot + vue

news2024/11/24 3:29:15

文章目录

  • 1、简要介绍
  • 2、数据库设计
  • 3、解决的问题
    • 1、图片和音频的上传和存储
    • 2、分页功能
  • 4、数据返回


也算是进行了半个学期,跟着老师讲的进行

后端使用SpringBoot 前端 vue + layui
jdk 18

项目地址:gitee


1、简要介绍

  只有管理端,但是对用户端的判断功能在数据库中已经体现,

  实现了mp3音频文件和图片文件的上传,原理是存储在静态资源中,数据库中存的也是路径而已

以下为部分截图,整体风格亦是如此

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

2、数据库设计


CREATE TABLE `role`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '角色id',
  `role_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色名称',
  `role_status` int NULL DEFAULT NULL COMMENT '角色状态  0 不可用  1 可用',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `dis` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `rule` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;


CREATE TABLE `singer`  (
  `id` int UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `sex` tinyint NULL DEFAULT NULL,
  `pic` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `birth` datetime NULL DEFAULT NULL,
  `location` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `introduction` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 44 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

CREATE TABLE `song`  (
  `id` int UNSIGNED NOT NULL AUTO_INCREMENT,
  `singer_id` int UNSIGNED NOT NULL,
  `name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `introduction` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '发行时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `pic` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `lyric` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL,
  `url` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 124 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

CREATE TABLE `sys_user`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户名',
  `nick_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '昵称',
  `gender` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '性别',
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密码  密文存储 ',
  `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '手机号码',
  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '1 可用   0 禁用',
  `image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '服务器路径',
  `created_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建者',
  `role_uid` int NULL DEFAULT NULL COMMENT '角色  严格遵循外键约束,但在表设计时候,不使用约束语句',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

3、解决的问题

1、图片和音频的上传和存储

  首先肯定是要有一个对于存储文件的配置,然后,在前端发送的时候,注意使用
post + headers: { 'content-type': 'multipart/form-data' } 的格式,

package com.whd.system.controller;

import com.github.pagehelper.util.StringUtil;
import com.whd.system.common.AxiosResult;
import com.whd.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.util.UUID;

@RestController
@RequestMapping("/fileup")
public class FileUpController {

    public static final String UPLOAD_PATH = "F:\\javaweb\\study\\spingBootMaven\\src\\main\\resources\\upload\\";

    @PostMapping("/image")
    public AxiosResult<String> upload(@RequestParam(value = "name") String name,  MultipartFile photo, HttpServletRequest request) throws IOException {

        if(name==null || name.equals("")){
            return AxiosResult.error("参数错误");
        }

        String extension = StringUtils.getFilenameExtension(photo.getOriginalFilename());

        String fileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + extension;

        String curDateStr = LocalDate.now().toString();


        File file = new File(UPLOAD_PATH+name+"\\"+ curDateStr);
        if (!file.exists()) {
            file.mkdirs();
        }

        photo.transferTo(new File(UPLOAD_PATH +name+ "\\" + curDateStr + "/" + fileName));

        return AxiosResult.success(name+ "\\" + curDateStr + "/" + fileName);
    }

    @PostMapping("/video")
    public AxiosResult<String> uploadViedo(@RequestParam(value = "name") String name,  MultipartFile video, HttpServletRequest request) throws IOException {

        name+="\\viedo";

        if(!video.getContentType().equals("audio/mpeg")) {
            return AxiosResult.error("只允许上传mp3格式的音频文件");
        }

        String extension = StringUtils.getFilenameExtension(video.getOriginalFilename());

        String fileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + extension;

        String curDateStr = LocalDate.now().toString();
        System.out.println(UPLOAD_PATH+name+"\\"+ curDateStr);

        File file = new File(UPLOAD_PATH+name+"\\"+ curDateStr);
        if (!file.exists()) {
            file.mkdirs();
        }

        video.transferTo(new File(UPLOAD_PATH +name+ "\\" + curDateStr + "/" + fileName));

        return AxiosResult.success(name+ "\\" + curDateStr + "/" + fileName);
    }


}

2、分页功能

  通过自定义的一个组件(当然不是我写的),在后端进行判断处理,其实没有想到那么复杂

组件如下:

<script>
Vue.component('zpagenav', {
	template: `<nav class="zpagenav">` +
		`<ul class="page-ul">` +
		`<li v-bind:key="index" v-for="(item,index) in pageList" v-bind:class ="item.class" @click.stop="setPage(item)" v-html="item.html">` +
		`</li>` +
		`</ul>` +
		`<span class="total">共 {{total}} 条</span>` +
		`</nav>`,
	props: {
		prevHtml: String,
		nextHtml: String,
		page: Number,
		total: Number,
		pageSize: Number,
		maxPage: Number
	},
	computed: {
		pageList: function() {
			var _this = this,
				pageList = [];
			let pageCount = Math.ceil(_this.total / _this.pageSize);
			let page = _this.page;
			let prevHtml = _this.prevHtml ? _this.prevHtml : '&lt;';
			let nextHtml = _this.nextHtml ? _this.nextHtml : '&gt;';
			let maxPage = _this.maxPage ? _this.maxPage : 9;

			let hasPrev = page > 1;
			let hasNext = page < pageCount;

			//上一页
			pageList.push({
				class: hasPrev ? '' : 'disabled',
				page: hasPrev ? page - 1 : page,
				html: prevHtml
			});

			//首页
			pageList.push({
				class: page == 1 ? 'active' : '',
				page: 1,
				html: 1
			});

			var p0 = Math.floor(maxPage / 2);
			var p1 = 1 + 2 + p0; //首页+省略至少2个页码+中间页面数的一半

			var start, end;
			if(page >= p1) {
				start = page - p0;
				//前置省略号
				pageList.push({
					class: 'dot',
					page: page,
					html: '...'
				});
			} else {
				start = 2;
			}

			var p2 = page + p0;
			if(p2 < pageCount) {
				end = p2;
			} else {
				end = pageCount - 1;
			}

			//页码列表
			for(let i = start; i <= end; i++) {
				pageList.push({
					class: page == i ? 'active' : '',
					page: i,
					html: i
				});
			}

			if(end < pageCount - 1) {
				//后置省略号
				pageList.push({
					class: 'dot',
					page: page,
					html: '...'
				});
			}

			//尾页
			if(pageCount > 1) {
				pageList.push({
					class: page == pageCount ? 'active' : '',
					page: pageCount,
					html: pageCount
				});
			}

			//下一页
			pageList.push({
				class: hasNext ? '' : 'disabled',
				page: hasNext ? page + 1 : page,
				html: nextHtml
			});

			return pageList;
		}
	},
	methods: {
		setPage: function(item) {
			
			if(item.class == '') {
				this.$emit('pagehandler', item.page);
			}
		}
	}
});

</script>

<style>
.zpagenav {
	text-align: center;
	-webkit-user-select: none;
}

.zpagenav {
	font-family: arial;
	color: #48576a;
}

.zpagenav ul {
	display: inline-block;
	margin: 20px 20px;
	padding: 0;
}

.zpagenav ul li {
	display: inline-block;
	margin: 0;
	padding: 0 4px;
	border: 1px solid #d1dbe5;
	border-right: 0;
	background: #fff;
	font-size: 13px;
	min-width: 28px;
	height: 28px;
	line-height: 28px;
	cursor: pointer;
	box-sizing: border-box;
	text-align: center;
}

.zpagenav ul li:last-child {
	border-right: 1px solid #d1dbe5;
}

.zpagenav ul li:hover {
	color: #20a0ff;
}

.zpagenav ul li.active {
	border-color: #20a0ff;
	background-color: #20a0ff;
	color: #fff;
	cursor: default;
}

.zpagenav ul li.active:hover {
	color: #fff;
}

.zpagenav ul li.disabled {
	cursor: not-allowed;
	color: #e4e4e4;
}

.zpagenav ul li.dot {
	cursor: default;
}

</style>


使用的时候,注意引入该文件,和该文件的样式文件,然后,将这一坨复制到分页的地方

      <div class="page">
        <div class="wrap">
          <zpagenav v-bind:page="page" v-bind:page-size="pageSize" v-bind:total="total" v-bind:max-page="maxPage"
            v-on:pagehandler="pageHandler">
          </zpagenav>
        </div>
      </div>

注意,在vue 的 data 中加上 page: 1, pageSize: 10, total: 0, maxPage: 5,这三个属性,
然后,就是后端处理返回数据了,正常查询结果,通过 PageHelper PageInfo进行分页处理

处理逻辑如下例子:

 @PostMapping("/select/selectAllPage")
    public AxiosResult<PageResult<SongVo>> getAllSongByPage(@RequestBody PageVO pageVO){


        Integer page = pageVO.getPage();
        Integer size = pageVO.getSize();

        // 开始分页
        PageHelper.startPage(page, size);
        List<SongVo> songs=songMapper.getSongList();

        songs.forEach(song -> {
            song.setPic(PIC_URL + song.getPic());
            song.setUrl(PIC_URL + song.getUrl());
        });

        PageInfo<SongVo> pageInfo = new PageInfo<>(songs);

        //将数据封装在自己写的PageResult
        PageResult<SongVo> pageResult = new PageResult<>();
        pageResult.setPage(pageInfo.getPageNum());
        pageResult.setTotalPage(pageInfo.getPages());
        pageResult.setList(pageInfo.getList());
        pageResult.setTotal(pageInfo.getTotal());
        pageResult.setPageSize(pageInfo.getPageSize());

        return AxiosResult.success(pageResult);
    }

对于AxiosResult也是自己写的一个实体类, 用于返回信息和状态码, 具体代码可查看项目中的代码:
对于PageResult 类

@Data
public class PageResult<T> {
    private int page;
    private int pageSize;
    private long total;
    private List<T> list;
    private int totalPage;
}

PageVO 类

@Data
public class PageVO {
    private Integer page=1;//用户查询的第几页
    private Integer size=10;//每页展示的数量
}

4、数据返回

  通过SpringBoot返回的数据类型,会自动转为json格式,但是上面所提到的AxiosResult也不是必须的,但是这样子看起来更方便,该类可以作为模板重复使用

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

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

相关文章

俄罗斯ozon爆款推荐丨ozon学生受众产品

在俄罗斯电商平台OZON上&#xff0c;学生受众是一个庞大且活跃的群体。为了满足他们的需求&#xff0c;OZON平台上涌现出了一系列受学生欢迎的爆款产品。以下是一些针对学生受众的OZON爆款推荐&#xff1a; OZON选品工具&#xff1a;D。DDqbt。COM/74rD Top1 UNO纸牌游戏 俄语…

线程本地化存储如何保证线程安全

线程本地化存储如何保证线程安全 1、背景2、详细分析1、背景 在并发编程中,可能最害怕听到一个词就是线程不安全。因为它意味着程序运行的时候,可能出现数据的读取或写入不准确等情况发生, 2、详细分析 可能对于每个工程师来说都不陌生,就是我们工作中常见的一个环节,…

图片怎么弄成黑白的?关于将图片改成黑白的几种方法

图片怎么弄成黑白的&#xff1f;黑白照片以其独特的艺术魅力和经典的视觉效果&#xff0c;依然在摄影和图像处理中占据重要地位。无论是为了追求怀旧的氛围&#xff0c;还是为了突出图像的构图和光影效果&#xff0c;许多人都希望将彩色图片转换成黑白图片。这不仅可以赋予图像…

Tomcat Websocket应用实例研究

概述 本文介绍了如何根据Tomcat给出的websocket实例&#xff0c;通过对实例的学习&#xff0c;定制自己基于websocket的应用。 环境及版本&#xff1a; Ubuntu 22.04.4 LTSApache Tomcat/10.1.20openjdk 11.0.23 2024-04-16浏览器&#xff1a;Chrome 相关资源及链接 Class…

大模型精调:实现高效迁移学习的艺术

在人工智能领域&#xff0c;大型预训练模型&#xff08;以下简称“大模型”&#xff09;已经取得了令人瞩目的成果。这些模型通过在海量数据上进行预训练&#xff0c;能够捕捉到丰富的特征信息&#xff0c;为各种下游任务提供强大的支持。然而&#xff0c;如何将这些大模型应用…

如何用Vue3打造一个炫酷的树状图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 基于 Vue.js 的 Treemap 可视化组件 应用场景介绍 Treemap 可视化组件是一种强大的工具&#xff0c;用于以直观的方式展示分层数据。它将数据点绘制为矩形&#xff0c;其中每个矩形的大小与数据点的大小成正比…

【牛客面试必刷TOP101】Day33.BM70 兑换零钱(一)和BM71 最长上升子序列(一)

文章目录 前言一、BM70 兑换零钱(一)题目描述题目解析二、BM71 最长上升子序列(一)题目描述题目解析总结 前言 一、BM70 兑换零钱(一) 题目描述 描述&#xff1a; 给定数组arr&#xff0c;arr中所有的值都为正整数且不重复。每个值代表一种面值的货币&#xff0c;每种面值的货币…

C++ 60 之 虚析构和纯虚析构

#include <iostream> #include <string> #include <cstring> using namespace std;class Animal13{ public:Animal13(){cout << "Animal的默认构造函数" << endl;}virtual void speak(){cout << "动物叫" << en…

SD卡可以格式化成NTFS吗 SD卡Mac怎么读取内容

SD卡作为便携式存储媒介&#xff0c;广泛应用于我们的日常生活与工作之中。而NTFS&#xff0c;作为一种先进的文件系统&#xff0c;因其强大的功能和安全性&#xff0c;在Windows平台备受青睐。然而&#xff0c;当谈及将SD卡格式化为NTFS这一话题时&#xff0c;用户的疑惑随之而…

每日一练:攻防世界:Ditf

这是难度1的题吗&#xff1f;&#xff1f;&#xff1f; 拿到一个png图片&#xff0c;第一反应就是CRC爆破&#xff0c;结果还真的是高度被修改了 这里拿到一个字符串&#xff0c;提交flag结果发现不是&#xff0c;那么只可能是密钥之类的了 看看有没有压缩包&#xff0c;搜索…

超图论文细品——2019年AAAI《Hypergraph Neural Networks》

我是“导航” 1 摘要1.1 简介1.2 问题描述 2 超图2.1 图和超图对比 参考 1 摘要 1.1 简介 文章提出了一种名为超图神经网络的框架&#xff0c;用于高维数据的表示学习。 该方法英文称呼为 Hypergraph Neural Networks&#xff0c;简写为 HGNN。 1.2 问题描述 传统的 GNN 是…

多模态大模型通用模式

MM-LLMs&#xff08;多模态大模型&#xff09;是目前比较新的和实用价值越发显著的方向。其指的是基于LLM的模型&#xff0c;具有接收、推理和输出多模态信息的能力。这里主要指图文的多模态。 代表模型&#xff1a;GPT-4o、Gemini-1.5-Pro、GPT-4v、Qwen-VL、CogVLM2、GLM4V、…

服务器测试之硬盘规格扫盲贴

最近整理了AVL系统里的SSD相关规格信息&#xff0c;来个了解硬盘规格信息的扫盲贴,过程很曲折&#xff0c;但是认为学习一下相关规格参数还是很有用的 1.什么是硬盘 硬盘是计算机最主要的存储设备&#xff0c;平常买电脑的时候看到的配置24G1T里的1T就是硬盘&#xff0c;计算机…

ECharts 词云案例三:2024年阅读关键词

ECharts 词云案例三&#xff1a;2024年阅读关键词 引言 在数据可视化领域&#xff0c;ECharts 以其强大的功能性和灵活性&#xff0c;成为开发者和设计师的首选工具之一。继上一篇关于 ECharts 词云图的详细介绍后&#xff0c;本文将探索词云图的进阶应用——使用蒙版来创造更…

【Linux】—在Linux中搭建Python环境

文章目录 前言一、检查Linux系统是否自带Python版本。二、安装依赖包(重要)三、下载Python-3.9.5安装包四、下载完成后&#xff0c;通过xftp6上传到Linux服务器上五、解压Python安装包六、编译安装Python七、配置Python环境变量八、运行Python&#xff0c;查看是否可用九、pyth…

如何用Excel随机抽取幸运儿

在举行年会等活动&#xff0c;会在大屏幕互动随机滚动抽取幸运观众&#xff0c;有专门开发的软件或程序&#xff1b; 对于我们日常工作中有时会遇到&#xff0c;如何在群体中随机抽取部分幸运儿的问题&#xff1f; 除了抓阄&#xff0c;当然也可以用Excel解决哦&#xff0c;今…

适合小白学习的项目1906java Web智慧食堂管理系统idea开发mysql数据库web结构java编程计算机网页源码servlet项目

一、源码特点 java Web智慧食堂管理系统是一套完善的信息管理系统&#xff0c;结合java 开发技术和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 前段主要技术 bootstra…

现在市面上哪个大大数据信用查询平台比较好用?

在当今信息化和数字化的时代&#xff0c;信用查询平台的重要性愈发突出&#xff0c;特别是在个人贷款、信用卡申请和金融服务领域。选择一个优秀的大数据信用查询平台&#xff0c;不仅可以帮助用户全面了解自己的信用状况&#xff0c;还能提供针对性的解读和建议&#xff0c;帮…

中国天辰×蓝卓丨共创行业级工业操作系统,加速培育新质生产力!

6月17日&#xff0c;中国天辰工程有限公司&#xff08;以下简称“中国天辰”&#xff09;党委委员、总经理梁军湘一行莅临蓝卓&#xff0c;双方就工业互联网平台合作进行座谈交流。蓝卓总经理谭彰、副总经理蓝照斌、总经理助理俞益标&#xff0c;以及中控技术副总裁吴才宝、大客…

阿里又出AI神器,颠覆传统图像编辑,免费开源!

文章首发于公众号&#xff1a;X小鹿AI副业 大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 最近阿里开源了 Mi…