1、后端编写
1.1 Service服务层
package com.gmw.musicserver.service;
import com.gmw.musicserver.entity.Song;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 歌曲表 服务类
* 歌曲service接口
* </p>
*
* @author 未进化的程序猿
* @since 2022-01-26
*/
public interface SongService extends IService<Song> {
/**
*增加
*/
public boolean insertSong(Song song);
/**
*修改
*/
public boolean updateSong(Song song);
/**
* 删除
*/
public boolean deleteSong(Integer id);
/**
* 根据主键查询整个对象
*/
public Song selectByPrimaryKey(Integer id);
/**
* 查询所有歌曲
*/
public List<Song> allSong();
/**
* 根据歌名模糊查询列表
*/
public List<Song> songOfName(String name);
/**
* 根据歌手id查询
*/
public List<Song> songOfSingerId(Integer singerId);
}
package com.gmw.musicserver.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gmw.musicserver.entity.Song;
import com.gmw.musicserver.mapper.SongMapper;
import com.gmw.musicserver.service.SongService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 歌曲表 服务实现类
* </p>
*
* @author 未进化的程序猿
* @since 2022-01-26
*/
@Service
public class SongServiceImpl extends ServiceImpl<SongMapper, Song> implements SongService {
/**
* 添加歌曲
* @param song
* @return
*/
@Override
public boolean insertSong(Song song) {
return this.baseMapper.insert(song) > 0;
}
/**
* 更新歌曲
* @param song
* @return
*/
@Override
public boolean updateSong(Song song) {
return this.baseMapper.updateById(song) > 0;
}
/**
* 删除歌曲
* @param id
* @return
*/
@Override
public boolean deleteSong(Integer id) {
return this.baseMapper.deleteById(id) > 0;
}
/**
* 根据主键id查询歌曲对象
* @param id
* @return
*/
@Override
public Song selectByPrimaryKey(Integer id) {
return this.baseMapper.selectById(id);
}
/**
* 查询所有的歌曲
* @return
*/
@Override
public List<Song> allSong() {
return this.baseMapper.selectList(null);
}
/**
* 根据歌曲名称模糊查询所有的歌曲
* @param name
* @return
*/
@Override
public List<Song> songOfName(String name) {
QueryWrapper<Song> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name",name);
return this.baseMapper.selectList(queryWrapper);
}
/**
* 根据歌手名称查询所有的歌曲
* @param singerId
* @return
*/
@Override
public List<Song> songOfSingerId(Integer singerId) {
QueryWrapper<Song> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("singer_id",singerId);
return this.baseMapper.selectList(queryWrapper);
}
}
1.2 Controller控制层
package com.gmw.musicserver.controller;
import com.gmw.musicserver.commonutils.R;
import com.gmw.musicserver.entity.Singer;
import com.gmw.musicserver.entity.Song;
import com.gmw.musicserver.service.SongService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* <p>
* 歌曲表 前端控制器
* </p>
*
* @author 未进化的程序猿
* @since 2022-01-26
*/
@RestController
@RequestMapping("/musicserver/song")
public class SongController {
private static final Logger logger = LoggerFactory.getLogger(SongController.class);
@Autowired
public SongService songService;
@PostMapping(value = "/addSong")
public R addSong(HttpServletRequest request, @RequestParam("file")MultipartFile file){
//获取前端传来的参数
String singerId = request.getParameter("singerId").trim(); //所属歌手id
String name = request.getParameter("name").trim(); //歌名
String introduction = request.getParameter("introduction").trim(); //简介
String pic = "/img/songPic/tubiao.jpg"; //默认图片
String lyric = request.getParameter("lyric").trim(); //歌词
//上传歌曲文件
//先判断上传的文件是否为空
if(file.isEmpty()){
return R.error().message("歌曲上传失败!!");
}
//文件名=当前时间到毫秒+原来的文件名
String fileName = System.currentTimeMillis() + file.getOriginalFilename();
logger.info("文件名: {}",fileName);
//上传歌曲的文件路径
String filePath = System.getProperty("user.dir") + System.getProperty("file.separator")
+ "audio" + System.getProperty("file.separator") + "song";
logger.info("上传歌曲的文件地址: {}",filePath);
//如果文件路径不存在,新增该路径
File file1 = new File(filePath);
if(!file1.exists()){
file1.mkdir();
}
//实际的文件地址
String fileDist = filePath + System.getProperty("file.separator") + fileName;
logger.info("实际保存歌曲的文件地址: {}",fileDist);
File fileDest = new File(fileDist);
//存储到数据库里的相对文件地址
String storeUrlPath = "/audio/song/"+fileName;
logger.info("存储到数据库里的相对文件地址: {}",storeUrlPath);
try {
//保存上传图片
file.transferTo(fileDest);
//上传图片之后,保存歌曲的信息
Song song = new Song();
song.setSingerId(Integer.parseInt(singerId)); //歌手的ID
song.setName(name); //歌曲的名称
song.setIntroduction(introduction); //歌曲的专辑
song.setPic(pic); //歌曲的图片
song.setLyric(lyric); //歌曲的歌词
song.setUrl(storeUrlPath); //歌曲的播放地址
logger.info("歌曲对象: {}",song);
boolean flag = this.songService.insertSong(song);
if(flag){
return R.ok().message("添加歌曲成功!!").data("storeUrlPath",storeUrlPath);
}else {
return R.error().message("添加歌曲失败!!");
}
} catch (IOException e) {
return R.error().message("添加歌曲失败!!");
}
}
/**
* 根据歌手id查询歌曲
*/
@GetMapping(value = "/singer/detail")
public R songOfSingerId(HttpServletRequest request){
String singerId = request.getParameter("singerId");
List<Song> songList = this.songService.songOfSingerId(Integer.parseInt(singerId));
logger.info("根据歌手id查询歌曲: {}",songList);
return R.ok().data("list",songList);
}
/**
* 修改歌曲
*/
@PostMapping(value = "/updateSong")
public Object updateSong(HttpServletRequest request){
String id = request.getParameter("id").trim(); //主键
String name = request.getParameter("name").trim(); //歌名
String introduction = request.getParameter("introduction").trim();//专辑
String lyric = request.getParameter("lyric").trim(); //歌词
//保存到歌手的对象中
Song song = new Song();
song.setId(Integer.parseInt(id));
song.setName(name);
song.setIntroduction(introduction);
song.setLyric(lyric);
logger.info("编辑歌曲对象: {}",song);
boolean flag = this.songService.updateSong(song);
if(flag){ //保存成功
return R.ok().message("歌曲修改成功!!");
}
return R.error().message("歌曲修改失败!!");
}
/**
* 删除歌曲
*/
@GetMapping(value = "/deleteSong")
public R deleteSong(HttpServletRequest request){
String id = request.getParameter("id").trim(); //主键
//-TODO 先查询到数据库中对应的文件地址,删除掉它再进行下面的代码
//通过ID主键查询歌手对象
Song song = this.songService.selectByPrimaryKey(Integer.parseInt(id));
//获取歌曲图片
String songPic = song.getPic();
logger.info("歌曲图片: {}",songPic);
//如果文件的相对路径是/img/songPic/tubiao.jpg就没必要删除
//因为它是当作默认相对路径的,需要用到
if(!songPic.equals("/img/songPic/tubiao.jpg")){
//获取歌曲保存的文件目录
String songPath = System.getProperty("user.dir") + songPic;
logger.info("获取歌曲保存的文件目录: {}",songPath);
File file = new File(songPath);
if(file.isFile()){
//判断如果是文件的话,就删除文件
boolean isDelete = file.delete();
logger.info("是否删除成功: {}",isDelete);
if(!isDelete){
return R.error().message("删除歌曲失败!!");
}
}
}
//获取歌曲播放地址
String songUrl = song.getUrl();
logger.info("获取歌曲播放地址: {}",songUrl);
//获取歌曲保存的文件目录
String fileSongUrlPath = System.getProperty("user.dir") + songUrl;
logger.info("获取歌曲播放地址: {}",fileSongUrlPath);
File delUrlFile = new File(fileSongUrlPath);
if(delUrlFile.isFile()){
//判断如果是文件的话,就删除文件
boolean isDelete = delUrlFile.delete();
logger.info("是否删除成功: {}",isDelete);
if(!isDelete){
return R.error().message("删除歌曲失败!!");
}
}
boolean flag = this.songService.deleteSong(Integer.parseInt(id));
if(flag){
return R.ok().message("删除歌曲成功!!");
}
return R.error().message("删除歌曲失败!!");
}
/**
* 更新歌曲图片
*/
@PostMapping(value = "/updateSongPic")
public R updateSongPic(@RequestParam("file") MultipartFile file, @RequestParam("id")int id){
/**
* 更新歌曲之前,必须把原来的歌曲图片删除掉
*/
//通过ID主键查询歌手对象
Song song = this.songService.selectByPrimaryKey(id);
//获取歌曲图片
String songPic = song.getPic();
logger.info("歌曲图片: {}",songPic);
//如果文件的相对路径是/img/songPic/tubiao.jpg就没必要删除
//因为它是当作默认相对路径的,需要用到
if(!songPic.equals("/img/songPic/tubiao.jpg")){
//获取歌曲保存的文件目录
String songPath = System.getProperty("user.dir") + songPic;
logger.info("获取歌曲保存的文件目录: {}",songPath);
File file1 = new File(songPath);
if(file1.isFile()){
file1.delete();
}
}
//开始更新歌曲图片
if(file.isEmpty()){
return R.error().message("上传歌曲失败!!");
}
//文件名=当前时间到毫秒+原来的文件名
String fileName = System.currentTimeMillis()+file.getOriginalFilename();
//文件路径
String filePath = System.getProperty("user.dir")+System.getProperty("file.separator")+"img"
+System.getProperty("file.separator")+"songPic";
//如果文件路径不存在,新增该路径
File file1 = new File(filePath);
if(!file1.exists()){
file1.mkdir();
}
//实际的文件地址
File dest = new File(filePath+System.getProperty("file.separator")+fileName);
//存储到数据库里的相对文件地址
String storeAvatorPath = "/img/songPic/"+fileName;
try {
file.transferTo(dest);
Song song1 = new Song();
song1.setId(id); //歌曲ID
song1.setPic(storeAvatorPath); //歌曲图片相对地址
boolean flag = this.songService.updateSong(song1);
if(flag){
return R.ok().message("更新歌曲图片成功!!");
}else {
return R.error().message("更新歌曲图片失败!!");
}
} catch (IOException e) {
return R.error().message("更新歌曲图片失败!!");
}
}
/**
* 更新歌曲
*/
@PostMapping(value = "/updateSongUrl")
public R updateSongUrl(@RequestParam("file") MultipartFile avatorFile, @RequestParam("id")int id){
/**
* 更新歌曲之前,必须把原来的歌曲文件删除掉
*/
//通过ID主键查询歌手对象
Song song = this.songService.selectByPrimaryKey(id);
//获取歌曲播放地址
String songUrl = song.getUrl();
logger.info("获取歌曲播放地址: {}",songUrl);
//获取歌曲保存的文件目录
String fileSongUrlPath = System.getProperty("user.dir") + songUrl;
logger.info("获取歌曲播放地址: {}",fileSongUrlPath);
File delUrlFile = new File(fileSongUrlPath);
if(delUrlFile.isFile()){
delUrlFile.delete();
}
//开始文件上传
if(avatorFile.isEmpty()){
return R.error().message("文件上传失败!!");
}
//文件名=当前时间到毫秒+原来的文件名
String fileName = System.currentTimeMillis()+avatorFile.getOriginalFilename();
//文件路径
String filePath = System.getProperty("user.dir")+System.getProperty("file.separator")
+ "audio" + System.getProperty("file.separator") + "song";
//如果文件路径不存在,新增该路径
File file1 = new File(filePath);
if(!file1.exists()){
file1.mkdir();
}
//实际的文件地址
File dest = new File(filePath+System.getProperty("file.separator")+fileName);
//存储到数据库里的相对文件地址
String storeAvatorPath = "/audio/song/"+fileName;
try {
avatorFile.transferTo(dest);
Song song1 = new Song();
song1.setId(id);
song1.setUrl(storeAvatorPath);
boolean flag = this.songService.updateSong(song1);
if(flag){
return R.ok().message("更新歌曲播放文件成功!!");
}else {
return R.error().message("更新歌曲播放文件失败!!");
}
} catch (IOException e) {
return R.error().message("更新歌曲播放文件失败!!");
}
}
}
1.3 配置图片、音频定位各种文件或头像地址
package com.gmw.musicserver.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 定位各种文件或头像地址
*/
@Configuration
public class FileConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/**
* 歌手头像地址
*/
registry.addResourceHandler("/img/singerPic/**")
.addResourceLocations(
"file:" + System.getProperty("user.dir") + System.getProperty("file.separator")
+ "img" + System.getProperty("file.separator")
+ "singerPic" + System.getProperty("file.separator")
);
/**
* 歌单图片地址
*/
registry.addResourceHandler("/img/songListPic/**")
.addResourceLocations(
"file:" + System.getProperty("user.dir") + System.getProperty("file.separator")
+ "img" + System.getProperty("file.separator")
+ "songListPic" + System.getProperty("file.separator")
);
/**
* 歌曲图片地址
*/
registry.addResourceHandler("/img/songPic/**")
.addResourceLocations(
"file:" + System.getProperty("user.dir") + System.getProperty("file.separator")
+ "img" + System.getProperty("file.separator")
+ "songPic" + System.getProperty("file.separator")
);
/**
* 歌曲播放地址
*/
registry.addResourceHandler("/audio/song/**")
.addResourceLocations(
"file:" + System.getProperty("user.dir") + System.getProperty("file.separator")
+ "audio" + System.getProperty("file.separator")
+ "song" + System.getProperty("file.separator")
);
}
}
2、前端编写
<template>
<div class="table">
<div class="crumbs">
<i class="el-icon-tickets"></i>歌曲信息
</div>
<div class="container">
<div class="handle-box">
<el-button type="primary" size="mini" @click="delAll">批量删除</el-button>
<el-input v-model="select_word" size="mini" placeholder="请输入歌曲名" class="handle-input"></el-input>
<el-button type="primary" size="mini" @click="centerDialogVisible = true">添加歌曲</el-button>
</div>
</div>
<el-table size="mini" ref="multipleTable" border style="width:100%" height="680px" :data="data" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="40"></el-table-column>
<el-table-column label="歌曲图片" width="110" align="center">
<template slot-scope="scope">
<div class="song-img">
<img :src="getUrl(scope.row.pic)" style="width:100%"/>
</div>
<div class="play" @click="setSongUrl(scope.row.url,scope.row.name)">
<div v-if="toggle == scope.row.name">
<svg class="icon">
<use xlink:href="#icon-zanting"></use>
</svg>
</div>
<div v-if="toggle != scope.row.name">
<svg class="icon">
<use xlink:href="#icon-bofanganniu"></use>
</svg>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="name" label="歌手-歌名" width="120" align="center"></el-table-column>
<el-table-column prop="introduction" label="专辑" width="150" align="center"></el-table-column>
<el-table-column label="歌词" align="center">
<template slot-scope="scope">
<ul style="height:100px;overflow:scroll;">
<li v-for="(item,index) in parseLyric(scope.row.lyric)" :key="index">
{{item}}
</li>
</ul>
</template>
</el-table-column>
<el-table-column label="资源更新" align="center" width="100">
<template slot-scope="scope">
<el-upload :action="uploadUrl(scope.row.id)" :before-upload="beforeAvatorUpload"
:on-success="handleAvatorSuccess">
<el-button size="mini">更新图片</el-button>
</el-upload>
<br/>
<el-upload :action="uploadSongUrl(scope.row.id)" :before-upload="beforeSongUpload"
:on-success="handleSongSuccess">
<el-button size="mini">更新歌曲</el-button>
</el-upload>
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
background
layout = "total,prev,pager,next"
:current-page="currentPage"
:page-size="pageSize"
:total="tableData.length"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
<el-dialog title="添加歌曲" :visible.sync="centerDialogVisible" width="400px" center>
<el-form :model="registerForm" ref="registerForm" label-width="80px" action="" id="tf">
<div>
<label>歌名</label>
<el-input type="text" name="name"></el-input>
</div>
<div>
<label>专辑</label>
<el-input type="text" name="introduction"></el-input>
</div>
<div>
<label>歌词</label>
<el-input type="textarea" name="lyric"></el-input>
</div>
<div>
<label>歌曲上传</label>
<input type="file" name="file">
</div>
</el-form>
<span slot="footer">
<el-button size="mini" @click="centerDialogVisible = false">取消</el-button>
<el-button size="mini" @click="addSong">确定</el-button>
</span>
</el-dialog>
<el-dialog title="修改歌曲" :visible.sync="editVisible" width="400px" center>
<el-form :model="form" ref="form" label-width="80px">
<el-form-item prop="name" label="歌手-歌名" size="mini">
<el-input v-model="form.name" placeholder="歌手-歌名"></el-input>
</el-form-item>
<el-form-item prop="introduction" label="专辑" size="mini">
<el-input v-model="form.introduction" placeholder="专辑"></el-input>
</el-form-item>
<el-form-item prop="lyric" label="歌词" size="mini">
<el-input v-model="form.lyric" placeholder="歌词" type="textarea"></el-input>
</el-form-item>
</el-form>
<span slot="footer">
<el-button size="mini" @click="editVisible = false">取消</el-button>
<el-button size="mini" @click="editSave">确定</el-button>
</span>
</el-dialog>
<el-dialog title="删除歌曲" :visible.sync="delVisible" width="300px" center>
<div align="center">删除不可恢复,是否确定删除?</div>
<span slot="footer">
<el-button size="mini" @click="delVisible = false">取消</el-button>
<el-button size="mini" @click="deleteRow">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { mixin } from '../mixins/index';
import {mapGetters} from 'vuex';
import '@/assets/js/iconfont.js';
import {songOfSingerId,updateSong,delSong} from '../api/song/index';
export default {
mixins: [mixin],
data(){
return{
singerId: '', //歌手id
singerName: '', //歌手名
centerDialogVisible: false, //添加弹窗是否显示
editVisible: false, //编辑弹窗是否显示
delVisible: false, //删除弹窗是否显示
registerForm:{ //添加框
name: '',
singerName: '',
introduction: '',
lyric: ''
},
form:{ //编辑框
id: '',
name: '',
introduction: '',
lyric: ''
},
tableData: [],
tempData: [],
select_word: '',
pageSize: 5, //分页每页大小
currentPage: 1, //当前页
idx: -1, //当前选择项
multipleSelection: [], //哪些项已经打勾
toggle: false //播放器的图标状态
}
},
computed:{
...mapGetters([
'isPlay'
]),
//计算当前搜索结果表里的数据
data(){
return this.tableData.slice((this.currentPage - 1) * this.pageSize,this.currentPage * this.pageSize)
}
},
watch:{
//搜索框里面的内容发生变化的时候,搜索结果table列表的内容跟着它的内容发生变化
select_word: function(){
if(this.select_word == ''){
this.tableData = this.tempData;
}else{
this.tableData = [];
for(let item of this.tempData){
if(item.name.includes(this.select_word)){
this.tableData.push(item);
}
}
}
}
},
created(){
this.singerId = this.$route.query.id;
this.singerName = this.$route.query.name;
this.getData();
},
destroyed() {
this.$store.commit('setIsPlay',false);
},
methods:{
//获取当前页
handleCurrentChange(val){
this.currentPage = val;
},
//查询所有歌手
getData(){
this.tempData = [];
this.tableData = [];
songOfSingerId(this.singerId).then(res => {
this.tempData = res.data.list;
this.tableData = res.data.list;
this.currentPage = 1;
})
},
//添加歌手
addSong(){
let _this = this;
var form = new FormData(document.getElementById('tf'));
form.append('singerId',this.singerId);
form.set('name',this.singerName+'-'+form.get('name'));
if(!form.get('lyric')){
form.set('lyric','[00:00:00]暂无歌词');
}
var req = new XMLHttpRequest();
req.onreadystatechange = function(){
//req.readyState == 4 获取到返回的完整数据
//req.status == 200 和后台正常交互完成
if(req.readyState == 4 && req.status == 200){
let res = JSON.parse(req.response);
if(res.code){
_this.getData();
_this.registerForm = {};
_this.notify(res.msg,'success');
}else{
_this.notify('保存失败','error');
}
}
}
req.open('post',`${_this.$store.state.HOST}/musicserver/song/addSong`,false);
req.send(form);
_this.centerDialogVisible = false;
},
//弹出编辑页面
handleEdit(row){
this.editVisible = true;
this.form = {
id: row.id,
name: row.name,
introduction: row.introduction,
lyric: row.lyric
}
},
//保存编辑页面修改的数据
editSave(){
let params = new URLSearchParams();
params.append('id',this.form.id);
params.append('name',this.form.name);
params.append('introduction',this.form.introduction);
params.append('lyric',this.form.lyric);
updateSong(params)
.then(res => {
if(res.code == 20000){
this.getData();
this.notify("修改成功","success");
}else{
this.notify("修改失败","error");
}
})
.catch(err => {
console.log(err);
});
this.editVisible = false;
},
//更新图片
uploadUrl(id){
return `${this.$store.state.HOST}/musicserver/song/updateSongPic?id=${id}`
},
//删除一名歌手
deleteRow(){
delSong(this.idx)
.then(res => {
if(res.code == 20000){
this.getData();
this.notify("删除成功","success");
}else{
this.notify("删除失败","error");
}
})
.catch(err => {
console.log(err);
});
this.delVisible = false;
},
//解析歌词
parseLyric(text){
let lines = text.split("\n");
let pattern = /\[\d{2}:\d{2}.(\d{3}|\d{2})\]/g;
let result = [];
for(let item of lines){
let value = item.replace(pattern,'');
result.push(value);
}
return result;
},
//上传歌曲之前的校验
beforeSongUpload(file){
var testMsg = file.name.substring(file.name.lastIndexOf('.') + 1);
if(testMsg!='mp3'){
this.$message({
message: '上传文件只能是mp3格式',
type: 'error'
});
return false;
}
return true;
},
//上传歌曲成功之后要做的工作
handleSongSuccess(res){
let _this = this;
if(res.code == 20000){
_this.getData();
_this.$notify({
title: '上传成功',
type: 'success'
});
}else{
_this.$notify({
title: '上传失败',
type: 'error'
});
}
},
//更新歌曲url
uploadSongUrl(id){
return `${this.$store.state.HOST}/musicserver/song/updateSongUrl?id=${id}`
},
//切换播放歌曲
setSongUrl(url,name) {
this.toggle = name;
this.$store.commit('setUrl',this.$store.state.HOST + url);
if(this.isPlay){
this.$store.commit('setIsPlay',false);
}else{
this.$store.commit('setIsPlay',true);
}
}
}
}
</script>
<style scoped>
.handle-box{
margin-bottom: 20px;
}
.song-img{
width: 100%;
height: 80px;
border-radius: 5px;
margin-bottom: 5px;
overflow: hidden;
}
.handle-input{
width: 300px;
display: inline-block;
}
.pagination{
display: flex;
justify-content: center;
}
.play {
position: absolute;
z-index: 100;
width: 80px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
top: 18px;
left: 15px;
}
.icon {
width: 2em;
height: 2em;
color: white;
fill: currentColor;
overflow: hidden;
}
</style>
2.1 添加歌曲
<el-dialog title="添加歌曲" :visible.sync="centerDialogVisible" width="400px" center>
<el-form :model="registerForm" ref="registerForm" label-width="80px" action="" id="tf">
<div>
<label>歌名</label>
<el-input type="text" name="name"></el-input>
</div>
<div>
<label>专辑</label>
<el-input type="text" name="introduction"></el-input>
</div>
<div>
<label>歌词</label>
<el-input type="textarea" name="lyric"></el-input>
</div>
<div>
<label>歌曲上传</label>
<input type="file" name="file">
</div>
</el-form>
<span slot="footer">
<el-button size="mini" @click="centerDialogVisible = false">取消</el-button>
<el-button size="mini" @click="addSong">确定</el-button>
</span>
</el-dialog>
:visible.sync=”centerDialogVisible” 当centerDialogVisible为true时,会弹出文本输入框,否则隐藏
编写请求后端接口方法
import {get,post} from '../http'
//============歌曲相关================
//根据歌手id查询歌曲
export const songOfSingerId =(id) => get(`musicserver/song/singer/detail?singerId=${id}`);
//编辑歌曲
export const updateSong = (params) => post(`musicserver/song/updateSong`,params);
//删除歌曲
export const delSong = (id) => get(`musicserver/song/deleteSong?id=${id}`);
编写添加歌曲方法
//添加歌手
addSong(){
let _this = this;
var form = new FormData(document.getElementById('tf'));
form.append('singerId',this.singerId); //添加歌手的id到form中
form.set('name',this.singerName+'-'+form.get('name')); //设置歌曲的名称格式为:歌手名称-歌曲名称
if(!form.get('lyric')){
form.set('lyric','[00:00:00]暂无歌词');
}
var req = new XMLHttpRequest();
req.onreadystatechange = function(){
//req.readyState == 4 获取到返回的完整数据
//req.status == 200 和后台正常交互完成
if(req.readyState == 4 && req.status == 200){
let res = JSON.parse(req.response);
if(res.code){
_this.getData();
_this.registerForm = {};
_this.notify(res.msg,'success');
}else{
_this.notify('保存失败','error');
}
}
}
req.open('post',`${_this.$store.state.HOST}/musicserver/song/addSong`,false);
req.send(form);
_this.centerDialogVisible = false;
},
2.2 查询/修改/删除跟歌手管理模块一样(省略)
2.3 歌词显示
解析歌词(歌词前面带有[00:00.22]格式的替换为空字符串)
//解析歌词
parseLyric(text){
let lines = text.split("\n");
let pattern = /\[\d{2}:\d{2}.(\d{3}|\d{2})\]/g; //歌词前面带有[00:00.22]格式的替换为空字符串
let result = [];
for(let item of lines){
let value = item.replace(pattern,'');
result.push(value);
}
return result;
},
进行歌词的解析
2.4 更新歌曲图片/更新歌曲文件
<el-upload :action="uploadUrl(scope.row.id)" :before-upload="beforeAvatorUpload"
:on-success="handleAvatorSuccess">
<el-button size="mini">更新图片</el-button>
</el-upload>
<br/>
<el-upload :action="uploadSongUrl(scope.row.id)" :before-upload="beforeSongUpload"
:on-success="handleSongSuccess">
<el-button size="mini">更新歌曲</el-button>
</el-upload>
1)更新歌曲图片
:action=”uploadUrl(scope.row.id)” 表示要访问的后台地址,并携带歌曲的id,通过id修改歌曲图像
//更新图片
uploadUrl(id){
return `${this.$store.state.HOST}/musicserver/song/updateSongPic?id=${id}`
},
:before-upload=”beforeAvatorUpload” 表示文件上传之前,进行哪些操作,比如:上传的文件类型、大小都可以做限制;
//上传图片之前的校验
beforeAvatorUpload(file){
const isJPG = (file.type === 'image/jpeg')||(file.type === 'image/png');
if(!isJPG){
this.$message.error('上传头像图片只能是jpg或png格式');
return false;
}
const isLt2M = (file.size / 1024 /1024) < 2;
if(!isLt2M){
this.$message.error('上传头像图片大小不能超过2MB');
return false;
}
return true;
},
:on-success=”handleAvatorSuccess” 表示上传成功后需要进行哪些操作,比如:提示上传成功或者失败
//上传图片成功之后要做的工作
handleAvatorSuccess(res){
let _this = this;
if(res.code == 20000){
_this.getData();
_this.$notify({
title: '上传成功',
type: 'success'
});
}else{
_this.$notify({
title: '上传失败',
type: 'error'
});
}
},
2)更新歌曲文件
:action=”uploadSongUrl(scope.row.id)” 表示要访问的后台地址,并携带歌曲的id,通过id修改歌曲图像
//更新歌曲url
uploadSongUrl(id){
return `${this.$store.state.HOST}/musicserver/song/updateSongUrl?id=${id}`
},
:before-upload=”beforeSongUpload” 表示文件上传之前,进行哪些操作,比如:上传的文件类型、大小都可以做限制;
//上传歌曲之前的校验
beforeSongUpload(file){
var testMsg = file.name.substring(file.name.lastIndexOf('.') + 1);
if(testMsg!='mp3'){
this.$message({
message: '上传文件只能是mp3格式',
type: 'error'
});
return false;
}
return true;
},
:on-success=”handleSongSuccess” 表示上传成功后需要进行哪些操作,比如:提示上传成功或者失败
//上传歌曲成功之后要做的工作
handleSongSuccess(res){
let _this = this;
if(res.code == 20000){
_this.getData();
_this.$notify({
title: '上传成功',
type: 'success'
});
}else{
_this.$notify({
title: '上传失败',
type: 'error'
});
}
},
2.5 页面播放歌曲
1)设置全局共享属性:id、url、isPlay
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state:{
HOST: 'http://127.0.0.1:8888',
isPlay: false, //是否播放中
url: '', //歌曲地址
id: '' //歌曲id
},
getters: { //获取共享属性的方法
isPlay: state => state.isPlay,
url: state => state.url,
id: state => state.id
},
mutations: { //设置共享属性的方法
setIsPlay: (state,isPlay) => {state.isPlay = isPlay},
setUrl: (state,url) => {state.url = url},
setId: (state,id) => {state.id = id}
}
})
export default store
2)创建SongAudio.vue组件,专门用来播放音乐
<template>
<div class="song-audio">
<audio id="player"
:src="url"
controls = "controls"
preload = "true"
@canplay="startPlay"
@ended="ended"
></audio>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
export default {
name: 'song-audio',
computed: {
...mapGetters([
'id',
'url',
'isPlay'
])
},
watch:{
//监听播放还是暂停
isPlay: function(){
this.togglePlay();
}
},
methods:{
//获取链接后准备播放
startPlay(){
let player = document.querySelector('#player');
//开始播放
player.play();
},
//播放完成之后触发
ended(){
this.isPlay = false
},
//开始、暂停
togglePlay() {
let player = document.querySelector('#player');
if(this.isPlay){
player.play();
}else{
player.pause();
}
}
}
}
</script>
<style>
.song-audio {
display: none;
}
</style>
3)在App.vue页面中,引入该组件
<template>
<div id="app">
<SongAudio />
<router-view></router-view>
</div>
</template>
<script>
import SongAudio from './components/SongAudio';
export default {
name: 'App',
components: {
SongAudio
}
}
</script>
<style>
</style>
4)在SongPage.vue歌曲页面中进行参数的设置
//切换播放歌曲
setSongUrl(url,name) {
this.toggle = name;
this.$store.commit('setUrl',this.$store.state.HOST + url);
if(this.isPlay){
this.$store.commit('setIsPlay',false);
}else{
this.$store.commit('setIsPlay',true);
}
}