目录

音乐播放器

项目功能:

项目框架:

项目的创建很重要:

数据库设计

在idea中配置数据库和xml

一.登录板块设计

1创建User类

2创建UserMapper和Controller接口

3.实现登录

4加密设置

5实现加密登录

二.上传音乐模块设计

1上传音乐的请求和响应

2创建MusicController类

3测试上传​编辑

4实现数据库上传

三.播放音乐设计

1请求和响应设计

2添加get方法

四.删除音乐模块设计

1删除单个音乐

2批量删除选中音乐

五.查询音乐模块设计

1请求和响应设计

2MusicMapper新增方法

3配置MusicMapper.xml

4MusicController新增方法

六.收藏/移除音乐模块设计

1添加音乐到lovemiusic

2查询喜欢的音乐

3移除收藏音乐

4完善删除音乐

七.前端页面实现

1登录界面

2上传界面

3音乐列表页面

4收藏页面

5配置拦截器


音乐播放器

实现一个小项目,在线音乐服务器

准备工作:idea(代码编写),apifox/postman(接口调试,我用的前者),一颗不怕出错的心

项目功能:

1、登录

2、上传音乐

3、删除指定音乐

4、查询音乐

5、收藏音乐

7、移除收藏

项目框架:

后端:

前端:

数据库:

首先实现后端方面的代码

用idea创建一个springboot项目,名称为musicserver---开发工具选择:SpringBootDevTools,Lombok,SpringWeb,Mybatis,MySql.

项目的创建很重要:

代码还没开始写,连项目都创建出错岂不是很难受

创建项目可能会遇到pom.xml报错,大概率是网络原因,一些包没有下载成功.特别注意maven的配置,建议仓库用内置,镜像用阿里云

设置好还是出错就去maven仓库官网下载报错的包,复制到自己的仓库,然后在pom.xml中修改合适的版本即可

数据库设计

创建数据库musicserver,建表user,music,lovemusic、

-- 数据库
drop database if exists `musicserver`;
create database if not exists `musicserver` character set utf8;
-- 使用数据库
use `musicserver`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`password` varchar(255) NOT NULL
);
INSERT INTO user(username,password)
VALUES("sg","$2a$10$Bs4wNEkledVlGZa6wSfX7eCSD7wRMO0eUwkJH0WyhXzKQJrnk85li");
-- 这是加密后的密码,后文会提到
INSERT INTO user(username,password)
VALUES("sg1","123456");
DROP TABLE IF EXISTS `music`;
CREATE TABLE `music` (
`id` int PRIMARY KEY AUTO_INCREMENT,
`title` varchar(50) NOT NULL,
`singer` varchar(30) NOT NULL,
`time` varchar(13) NOT NULL,
`url` varchar(1000) NOT NULL,
`userid` int(11) NOT NULL
);
​
DROP TABLE IF EXISTS `lovemusic`;
CREATE TABLE `lovemusic` (
`id` int PRIMARY KEY AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`music_id` int(11) NOT NULL
);

在idea中配置数据库和xml

application.properties

#配置数据库
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/musicserver?characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=root
#填你mysql的密码
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#配置xml
mybatis.mapper-locations=classpath:mybatis/**Mapper.xml
#配置springboot上传文件的大小,默认每个文件的配置最大为15Mb,单次请求的文件的总数不能大于100Mb
spring.servlet.multipart.max-file-size = 15MB
spring.servlet.multipart.max-request-size=100MB
# 配置springboot日志调试模式是否开启
debug=true
# 设置打印日志的级别,及打印sql语句
#音乐的上传路径
music.local.path=/自己规定路径即可/local/music
#日志级别:trace,debug,info,warn,error
#基本日志
logging.level.root=INFO
logging.level.com.example.musicserver.mapper=debug
#扫描的包:druid.sql.Statement类和frank包
logging.level.druid.sql.Statement=DEBUG
logging.level.com.example=DEBUG
​
​
​

一.登录板块设计

登录肯定是用户登录,所以应该有一个User类,根据SpringBoot框架,应该有对应的UserMapper和Controller接口来操作User;此外,这些User的信息都应该存储到数据库中,再根据Spring的IOC思想,我们应该运用Mybatis的知识,配置好相应的xml文件

1创建User类

为了方便管理,创建好包com.example.musicserver.model

package com.example.musicserver.model;
import lombok.Data;
@Data
public class User {private int id;private String username;private String password;
}

2创建UserMapper和Controller接口

2.1新建mapper包

@Mapper
public interface UserMapper {User login(User loginUser);
}

2.2配置UsserMapper.xml文件

resources目录-->mybatis-->UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.music.mapper.UserMapper">
​<select id="login" resultType="com.example.music.model.User">select * from user where username=#{username} and password=#{password};</select>
​
</mapper>

3.实现登录

3.1登录的请求和响应

请求:
{post,/user/logindata:{username,password}
}
响应:
{"status": 0,"message": "登录成功","data": {"id": xxxxx,"username": xxxxxx,"password": xxxxxxxx}
}

3.2响应体的具体设计,封装成一个类

musicserver下新建tools包,创建ResponseBodyMessage类

import lombok.Data;
​
@Data
public class ResponseBodyMessage <T> {private int status;private String message;private T data;
​public ResponseBodyMessage(int status, String message, T data) {this.status = status;this.message = message;this.data = data;}
}
​

tools下新建Constant类,存储后续用到的session请求常量,避免拼写错误带来的报错

public class Constant {public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY";
}
//使用枚举也行

3.3创建UserController类

musicserver下新建controller包

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserMapper userMapper;@RequestMapping("/login")public ResponseBodyMessage<User> login(@RequestParam String username, @RequestParam String password,HttpServletRequest request) {User userLogin = new User();userLogin.setUsername(username);userLogin.setPassword(password);User user = userMapper.login(userLogin);if(userInfo == null) {return new ResponseBodyMessage<>(-1,"用户名或者密码错误",user);} else {request.getSession().setAttribute("Constant.USERINFO_SESSION_KEY",user);return new ResponseBodyMessage<>(0,"登录成功",user);}}
}

运行MusicServerApplication.java

测试接口,点击发送

响应返回:"登录成功"即为成功

失败的话看返回的状态码,自己的mysql有没有启动,idea和mysql连接上没有

4加密设置

BCrypt加密:在pom.xml中添加依赖

<!-- security依赖包 (加密)-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>

在MusicServerApplication中添加

@SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})

这是因为在SpringBoot中,默认的Spring Security生效了的,此时的接口都是被保护的,我们需要通过验证才能正 常的访问。此时通过上述配置,即可禁用默认的登录验证

5实现加密登录

5.1在UserMapper中新增方法

 User selectByName(String username);

5.2UserMapper.xml添加配置

    <select id="selectByName" resultType="com.example.music.model.User">select * from user where username=#{username};</select>

5.3修改UserController类

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserMapper userMapper;//修改的地方//@Autowiredprivate BCryptPasswordEncoder bCryptPasswordEncoder;@RequestMapping("/login")public ResponseBodyMessage<User> login(@RequestParam String username,@RequestParam String password,HttpServletRequest request) {User userLogin = new User();userLogin.setUsername(username);userLogin.setPassword(password);User user = userMapper.login(userLogin);if (user == null) {System.out.println("登录失败");return new ResponseBodyMessage<>(-1,"error",user);} else {//修改的地方//boolean flag = bCryptPasswordEncoder.matches(password, user.getPassword());if(!flag) {return new ResponseBodyMessage<>(-1,"error",user);}System.out.println("登录成功");request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);return new ResponseBodyMessage<>(0,"success",user);}
}

5.4创建AppConfig类

musicserver下新建config包

@Configuration
public class AppConfig {@Beanpublic BCryptPasswordEncoder getBCryptPasswordEncoder() {return new BCryptPasswordEncoder();}
}

@Configuration:表明当前类是一个配置类,被注解的类内部包含有一个或多个被@Bean注解的方法,用于构建bean定义,初始化Spring容器。

@Bean注解:用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。

SpringIOC 容器管理一个或者多个bean,这些bean都需要在@Configuration注解下进行创建,在一个方法上使用@Bean注解就表明这个方法需要交给Spring进行管理

5.5验证加密登录

把刚才的username改为sg,你就会发现也可以登录成功了

二.上传音乐模块设计

1上传音乐的请求和响应

请求:
{post,/music/upload{singer,MultipartFile file},
}
响应:
{"status": 0,"message": "上传成功!","data": true
}

在model包下创建Music类,属性根据数据库的music表可知

import lombok.Data;
@Data
public class Music {private int id;private String title;private String singer;private String url;private String time;private int userid;
}

2创建MusicController类

@RestController
@RequestMapping("/music")
public class MusicController {//将路径封装到配置文件@Value("${music.local.path}")private String SAVE_PATH;@RequestMapping(value = "/upload")public ResponseBodyMessage<Boolean> insertMusic(@RequestParam String singer,@RequestParam("filename") MultipartFile file,HttpServletRequest req,HttpServletResponse resp) throws IOException {//没有session不创建HttpSession httpSession = req.getSession(false);//检查是否登录if (httpSession == null || httpSession.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {System.out.println("没有登录!");return new ResponseBodyMessage<>(-1, "没有登录!", false);}//上传到服务器String filenameAndType = file.getOriginalFilename();//xxx.mp3String path = SAVE_PATH + "/" + filenameAndType;File dest = new File(path);System.out.println("dest:=>" + dest.getPath());if (!dest.exists()) {dest.mkdir();}try {file.transferTo(dest);//上传文件到目标return new ResponseBodyMessage<>(0,"服务器上传成功!",true);} catch (IOException e) {e.printStackTrace();}return new ResponseBodyMessage<>(-1,"上传失败!",false);}
}

自己要规定一个路径来上传音乐,与application.properties音乐上传路径一致即可

3测试上传

4实现数据库上传

4.1定义MusicMapper接口

在mapper包下

@Mapper
public interface MusicMapper {public int insert(String title,String singer,String time,String url,int userid);
​
}
​

4.2定义MusicMapper.xml

mybatis下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.musicserver.mapper.MusicMapper"><insert id="insert">insert into music(title,singer,time,url,userid)values(#{title},#{singer},#{time},#{url},#{userid})</insert>
</mapper>

4.3在MusicController中引入MusicMapper

@Resource
private MusicMapper musicMapper;

4.4完善insertMusic方法

@RestController
@RequestMapping("/music")
public class MusicController {//将路径封装到配置文件@Value("${music.local.path}")private String SAVE_PATH;
​@Autowiredprivate MusicMapper musicMapper;
​
​@RequestMapping(value = "/upload")public ResponseBodyMessage<Boolean> insertMusic(@RequestParam String singer,@RequestParam("filename") MultipartFile file,HttpServletRequest req,HttpServletResponse resp) throws IOException {//没有session不创建HttpSession httpSession = req.getSession(false);//检查是否登录if (httpSession == null || httpSession.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {System.out.println("没有登录!");return new ResponseBodyMessage<>(-1, "没有登录!", false);}
​
​//上传到服务器String filenameAndType = file.getOriginalFilename();//xxx.mp3
​String path = SAVE_PATH + "/" + filenameAndType;File dest = new File(path);System.out.println("dest:=>" + dest.getPath());
​if (!dest.exists()) {dest.mkdir();}try {file.transferTo(dest);//上传文件到目标} catch (IOException e) {e.printStackTrace();return new ResponseBodyMessage<>(-1, "服务器上传失败", false);}
​//数据库上传assert filenameAndType != null;int index = filenameAndType.lastIndexOf(".");String title = filenameAndType.substring(0, index);
​User user = (User) httpSession.getAttribute(Constant.USERINFO_SESSION_KEY);int uerid = user.getId();//http请求String url = "/music/get?path=" + title;
​SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String time = sdf.format(new Date());
​
​try {int ret = 0;ret = musicMapper.insert(title, singer, time, url, uerid);if (ret == 1) {//跳转音列表return new ResponseBodyMessage<>(0, "数据库上传成功!", true);} else {return new ResponseBodyMessage<>(-1, "数据库上传失败", false);}} catch (BindingException e) {dest.delete();return new ResponseBodyMessage<>(-1, "数据库上传失败", false);}
​}

三.播放音乐设计

1请求和响应设计

请求:
{get,/music/get?path=xxx.mp3
}
响应:
{音乐数据本身的字节信息
}

2添加get方法

@RequestMapping("/get")public ResponseEntity<byte[]> get(String path) {File file = new File(SAVE_PATH + "/" + path);byte[] a = null;try {a = Files.readAllBytes(file.toPath());if (a == null) {return ResponseEntity.badRequest().build();}return ResponseEntity.ok(a);} catch (IOException e) {e.printStackTrace();}
​return ResponseEntity.badRequest().build();}

当然接口测试就很简单了

四.删除音乐模块设计

1删除单个音乐

1.1请求和响应设计

请求:
{post,/music/delete,id
}
响应:
{"status": 0,"message": "删除成功!","data": true
}

1.2MusicMapper添加方法

 Music findMusicById(int id);
​int deleteMusicById(int musicId);
​

1.3配置MusicMapper.xml

    <select id="findMusicById" resultType="com.example.music.model.Music">select * from music where id = #{id};</select>
​<delete id="deleteMusicById" parameterType="java.lang.Integer">delete from music where id = #{id};</delete>

1.4在MusicController中实现方法

    @RequestMapping("/delete")public ResponseBodyMessage<Boolean> deleteMusicById(@RequestParam String id) {//1.检查音乐是否存在 2.删除数据库 和 服务器int iid = Integer.parseInt(id);
​Music music = musicMapper.findMusicById(iid);if (music == null) {return new ResponseBodyMessage<Boolean>(-1, "没有要删除的音乐", false);
​} else {int ret = musicMapper.deleteMusicById(iid);
​if (ret == 1) {String fileName = music.getTitle();File file = new File(SAVE_PATH + "/" + fileName + ".mp3");
​if (file.delete()) {
​return new ResponseBodyMessage<Boolean>(0, "服务器中音乐删除成功", true);} else {return new ResponseBodyMessage<Boolean>(-1, "服务器中音乐删除失败", false);}} else {return new ResponseBodyMessage<Boolean>(-1, "数据库中音乐删除失败", false);}}
​
​}

2批量删除选中音乐

2.1请求和响应设计

请求:
{post,/music/deleteSel,data:{"id":id}
}
响应:
{"status": 0,"message": "批量删除成功","data": true
}

2.2新增deleteSelMusic方法

 @RequestMapping("/deleteSel")public ResponseBodyMessage<Boolean> deleteSelMusic(@RequestParam("id[]") List<Integer> id) {System.out.println("所有的ID : "+ id);//记录删除的音乐数量int sum = 0;
​for (int i = 0; i < id.size(); i++) {int musicId = id.get(i);Music music = musicMapper.findMusicById(musicId);if(music == null) {System.out.println("没有这个id的音乐");return new ResponseBodyMessage<>(-1, "没有要删除的音乐", false);}int ret = musicMapper.deleteMusicById(musicId);if(ret == 1) {
​int index = music.getUrl().lastIndexOf("=");String fileName = music.getUrl().substring(index+1);
​File file = new File(SAVE_PATH+"/"+fileName+".mp3");
​if(file.delete()) {sum += ret;}else {return new ResponseBodyMessage<>(-1,"服务器当中的音乐删除失败!",false);}}else {return new ResponseBodyMessage<>(-1,"数据库当中的音乐删除失败!",false);}}if(sum == id.size()) {System.out.println("整体删除成功!");return new ResponseBodyMessage<>(0,"音乐删除成功!",true);}else {System.out.println("整体删除失败!");return new ResponseBodyMessage<>(-1,"音乐删除失败!",false);}}

五.查询音乐模块设计

1请求和响应设计

若不传参就显示所有音乐

请求:
{get,/music/findmusic,data:{musicName:musicName},
}
响应:【不给musicName传参】
{"status": 0,"message": "查询到了歌曲的信息","data": []
}
响应:【给musicName传参】
{"status": 0,"message": "查询到了歌曲的信息","data": [
​]
}

2MusicMapper新增方法

    List<Music> findMusic();
​List<Music> findMusicByName(String name);

3配置MusicMapper.xml

<select id="findMusicByMusicName" resultType="com.example.musicserver.model.Music">select * from music where title like concat('%',#{musicName},'%')
</select>
<select id="findMusic" resultType="com.example.musicserver.model.Music">select * from music
</select>

4MusicController新增方法

@RequestMapping("/findmusic")public ResponseBodyMessage<List<Music>> findMusic(@RequestParam(required = false) String musicName) {
​List<Music> musicList;if(musicName != null) {musicList = musicMapper.findMusicByName(musicName);}else {musicList = musicMapper.findMusic();}return new ResponseBodyMessage<>(0,"查询到了所有的音乐",musicList);}

六.收藏/移除音乐模块设计

1添加音乐到lovemiusic

1.1请求和响应设计

请求:
{post,/lovemusic/likeMusicdata: id//音乐id
}
响应:
{"status": 0,"message": "点赞音乐成功","data": true
}

1.2实现LoveMusicMapper接口

@Mapper
public interface LoveMusicMapper {/*** 检查是否已经收藏过该音乐* @param userId* @param musicId* @return*/Music findLoveMusicByMusicIdAndUserId(int userId, int musicId);/*** 收藏音乐* @param userId* @param musicId* @return*/boolean insertLoveMusic(int userId, int musicId);
} 

1.2配置LoveMusicMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.musicserver.mapper.LoveMusicMapper"><!--根据用户ID和音乐ID查询收藏的音乐 --><select id="findLoveMusicByMusicIdAndUserId"resultType="com.example.musicserver.model.Music">select * from lovemusic where user_id=#{userId} and music_id=#{musicId}</select><insert id="insertLoveMusic">insert into lovemusic(user_id,music_id) values(#{userId},#{musicId})</insert>
</mapper>

1.3实现LoveMusicController

@RestController
@RequestMapping("/lovemusic")
public class LoveMusicController {
​@Resourceprivate LoveMusicMapper loveMusicMapper;
​@RequestMapping("/likeMusic")public ResponseBodyMessage<Boolean> likeMusic(@RequestParam String id,HttpServletRequest request) {
​int musicId = Integer.parseInt(id);System.out.println("musicId:" + musicId);//1、检查是否登录了HttpSession httpSession = request.getSession(false);if (httpSession == null || httpSession.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {System.out.println("没有登录!");return new ResponseBodyMessage<>(-1, "请登录后上传", false);}
​User user = (User) httpSession.getAttribute(Constant.USERINFO_SESSION_KEY);int userId = user.getId();System.out.println("userId:" + userId);
​Music music = loveMusicMapper.findLoveMusicByMusicIdAndUserId(userId, musicId);if (music != null) {return new ResponseBodyMessage<>(-1, "您之前收藏过这个音乐", false);}
​boolean effect = loveMusicMapper.insertLoveMusic(userId, musicId);if (effect) {return new ResponseBodyMessage<>(0, "收藏成功!", true);} else {return new ResponseBodyMessage<>(-1, "收藏失败!", false);}}
​
​}

2查询喜欢的音乐

2.1请求和响应

不传参就查询所有

请求:
{get,/lovemusic/findlovemusic,data:{musicName:musicName}
}
响应:
{"status": 0,"message": "查询到了所有的收藏的音乐","data": [
​]
}

2.2LoveMusicMapper新增方法

/**
* 如果没有传入具体的歌曲名,显示当前用户收藏的所有音乐
* @param userId
* @return
*/
List<Music> findLoveMusicByUserId(int userId);
/**
* 根据某个用户的ID和歌曲名称查询,某个用户收藏的音乐
* @param musicName
* @param userId
* @return
*/
List<Music> findLoveMusicBykeyAndUID(String musicName, int userId);

2.3LoveMusicMapper.xml

    <select id="findLoveMusicByUserId" resultType="com.example.music.model.Music">select m.* from lovemusic lm,music m where m.id = lm.music_id and lm.user_id=#{userId};</select><select id="findLoveMusicBykeyAndUID" resultType="com.example.music.model.Music">select m.* from lovemusic lm,music m where m.id = lm.music_id and lm.user_id=#{userId}and title like concat('%',#{musicName},'%');</select>

2.4LoveMusicController新增方法

    @RequestMapping("/findlovemusic")public ResponseBodyMessage<List<Music>> findLoveMusic(@RequestParam(required = false) String musicName,HttpServletRequest request) {//检查是否登录了HttpSession httpSession = request.getSession(false);if (httpSession == null || httpSession.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {System.out.println("没有登录!");return new ResponseBodyMessage<>(-1, "请登录后查找", null);}
​User user = (User) httpSession.getAttribute(Constant.USERINFO_SESSION_KEY);int userId = user.getId();System.out.println("userId:" + userId);
​List<Music> musicList;if (musicName == null) {musicList = loveMusicMapper.findLoveMusicByUserId(userId);} else {musicList = loveMusicMapper.findLoveMusicBykeyAndUID(musicName, userId);}return new ResponseBodyMessage<>(0, "查询到了所有的歌曲信息", musicList);}

3移除收藏音乐

3.1请求和响应

请求:
{post,/lovemusic/deletelovemusic,data:{id:id}
}
响应:
{"status": 0,"message": "取消收藏成功!","data": true
}   

3.2LoveMusicMapper新增方法

int deleteLoveMusic(int userId,int musicId);

3.3配置LoveMusicMapper.xml

<delete id="deleteLoveMusic" parameterType="java.lang.Integer">delete from lovemusic where user_id=#{userId} and music_id=#{musicId}
</delete>

3.4LoveMusicController

 @RequestMapping("/deletelovemusic")public ResponseBodyMessage<Boolean> deleteLoveMusic(@RequestParam String id, HttpServletRequest request) {int musicId = Integer.parseInt(id);
​HttpSession httpSession = request.getSession(false);if (httpSession == null || httpSession.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {System.out.println("没有登录!");return new ResponseBodyMessage<>(-1, "请登录后移除", null);}
​User user = (User) httpSession.getAttribute(Constant.USERINFO_SESSION_KEY);int userId = user.getId();
​int ret = loveMusicMapper.deleteLoveMusic(userId, musicId);
​if (ret == 1) {return new ResponseBodyMessage<>(0, "取消收藏成功!", true);} else {return new ResponseBodyMessage<>(-1, "取消收藏失败!", false);}}

4完善删除音乐

上面的删除音乐里面并不会删除lovemusic里面的,应该修改一下

4.1LoveMusicMapper新增方法

/**
* 当删除库中的音乐的时候,同步删除lovemusic中的数据
* @param musicId
* @return
*/
int deleteLoveMusicById(int musicId);

4.2配置LoveMusicMapper.xml

<delete id="deleteLoveMusicById" parameterType="java.lang.Integer">delete from lovemusic where music_id=#{musicId}
</delete>

4.3重写MusicMapper中的delete和deleteSel方法

   @RequestMapping("/delete")public ResponseBodyMessage<Boolean> deleteMusicById(@RequestParam String id) {//1.检查音乐是否存在 2.删除数据库 和 服务器int iid = Integer.parseInt(id);
​Music music = musicMapper.findMusicById(iid);if (music == null) {return new ResponseBodyMessage<Boolean>(-1, "没有要删除的音乐", false);
​} else {int ret = musicMapper.deleteMusicById(iid);
​if (ret == 1) {String fileName = music.getTitle();File file = new File(SAVE_PATH + "/" + fileName + ".mp3");
​if (file.delete()) {
​//同步删除lovemusic中的音乐loveMusicMapper.deleteLoveMusicByMusicId(iid);
​return new ResponseBodyMessage<Boolean>(0, "服务器中音乐删除成功", true);} else {return new ResponseBodyMessage<Boolean>(-1, "服务器中音乐删除失败", false);}} else {return new ResponseBodyMessage<Boolean>(-1, "数据库中音乐删除失败", false);}}
​
​}@RequestMapping("/deleteSel")public ResponseBodyMessage<Boolean> deleteSelMusic(@RequestParam("id[]") List<Integer> id) {System.out.println("所有的ID : "+ id);//记录删除的音乐数量int sum = 0;
​
​for (int i = 0; i < id.size(); i++) {int musicId = id.get(i);Music music = musicMapper.findMusicById(musicId);if(music == null) {System.out.println("没有这个id的音乐");return new ResponseBodyMessage<>(-1, "没有要删除的音乐", false);}int ret = musicMapper.deleteMusicById(musicId);if(ret == 1) {
​int index = music.getUrl().lastIndexOf("=");String fileName = music.getUrl().substring(index+1);
​File file = new File(SAVE_PATH+"/"+fileName+".mp3");
​if(file.delete()) {//同步检查lovemusic表当中 是否存在这个音乐loveMusicMapper.deleteLoveMusicByMusicId(musicId);sum += ret;//return new ResponseBodyMessage<>(0,"服务器当中的音乐删除成功!",true);}else {return new ResponseBodyMessage<>(-1,"服务器当中的音乐删除失败!",false);}}else {return new ResponseBodyMessage<>(-1,"数据库当中的音乐删除失败!",false);}}if(sum == id.size()) {System.out.println("整体删除成功!");return new ResponseBodyMessage<>(0,"音乐删除成功!",true);}else {System.out.println("整体删除失败!");return new ResponseBodyMessage<>(-1,"音乐删除失败!",false);}}
​
​

七.前端页面实现

下载jquery到static

1登录界面

login.html

​
<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width, initial-scale=1"/><meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/><title>音乐播放器登录页面</title>
​<!-- 1. 导入CSS的全局样式 --><link href="css/bootstrap.min.css" rel="stylesheet"><!-- 2. jQuery导入,建议使用1.9以上的版本 --><script src="js/jquery-3.1.1.min.js"></script><!-- 3. 导入bootstrap的js文件 --><!--<script src="js/bootstrap.min.js"></script>--><script type="text/javascript"></script><style>#body{background-image: url("images/3.png");/*background-size:100% 100%;background-attachment: fixed;*/}</style><script>// 核心业务逻辑$(function(){$("#submit").click(function(){var username = $("#user").val();var password = $("#password").val();
​if(username.trim() == "" || password.trim() == "") {alert("用户名或者密码不能为空!");return;}
​$.ajax({url:"/user/login",data:{"username":username,"password":password},type:"POST",dataType:"json",success:function(data) {console.log(data);if(data.status == 0) {alert("登录成功!");//跳转到指定的页面了window.location.href="list.html";}else{alert("登录失败,密码或者用户名错误!");$("#user").val("");$("#password").val("");}}});});});</script></head><body id="body"><div class="container" style="width: 400px;margin-top: 110px;background-color: rgba(255,255,255,0.8)"><h3 style="text-align: center;">音乐服务器登录界面</h3><div class="form-group" ><label for="user">用户名:</label><input type="text" name="username" class="form-control" id="user" placeholder="请输入用户名"/></div><div class="form-group"><label for="password">密码:</label><input type="password" name="password" class="form-control" id="password" placeholder="请输入密码"/></div>
​<hr/><div class="form-group" style="text-align: center;"><!--class="form-group"--><input style="width: 200px;height: 40px" id="submit" class="btn btn btn-primary" type="button" value="登录" ></div><!-- 出错显示的信息框 --><div class="alert alert-warning alert-dismissible" role="alert"><button type="button" class="close" data-dismiss="alert" ><span>&times;</span></button><!-- <strong id="message">您尚未进行登录,请您登录!</strong> --></div></div></body>
</html>

2上传界面

upload.html

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
​
</head>
<body>
<!--enctype="multipart/form-data"-->
<form method="POST" enctype="multipart/form-data" action="/music/upload">文件上传:<input type="file" name="filename"/>歌手名: <label><input type="text" name="singer" placeholder="请输入歌手名"/></label><input type="submit" value="上传"/>
</form>
</body>
</html>

3音乐列表页面

list.html

<!DOCTYPE html>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head><!-- 指定字符集 --><meta charset="utf-8"><!-- 使用Edge最新的浏览器的渲染方式 --><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。width: 默认宽度与设备的宽度相同initial-scale: 初始的缩放比,为1:1 -->
<!--    <meta name="viewport" content="width=device-width, initial-scale=1">--><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
​
​<title>在线音乐服务器</title>
​<link rel="shortcut icon" href="#" />
​<!-- 1. 导入CSS的全局样式 --><link href="css/bootstrap.min.css" rel="stylesheet"><!-- 2. jQuery导入,建议使用1.9以上的版本 --><script src="js/jquery-3.1.1.min.js"></script><!-- 3. 导入bootstrap的js文件 --><!-- <script src="js/bootstrap.min.js"></script>--><style type="text/css">td, th {text-align: center;}</style>
​<script type="text/javascript">// 核心代码实现$(function(){load();});
​
​
​//musicName可以传参  也可以不传参数function load(musicName) {
​$.ajax({
​url:"/music/findmusic",data:{"musicName": musicName},type:"GET",dataType:"json",success:function(obj) {console.log(obj);var data = obj.data;//数组
​var s = '';//data[i].id    data[i].singer  data[i].titlefor(var i = 0; i < data.length;i++) {var musicUrl = data[i].url+".mp3";console.log(musicUrl);
​s += '<tr>';s += '<th > <input id= "'+data[i].id+'" type="checkbox"> </th>';s += '<td>'+data[i].title+'</td>';s += '<td>'+data[i].singer+'</td>';s += '<td> <button class = "btn btn-primary"  οnclick="playerSong(\''+musicUrl+'\')"> 播放歌曲 </button>' +'</td>';s += '<td> <button class = "btn btn-primary"  οnclick="deleteInfo('+data[i].id+')"> 删除 </button>' +'<button class = "btn btn-primary"  οnclick="loveInfo('+data[i].id+')"> 喜欢 </button>' +'</td>';s += "</tr>"}$("#info").html(s);}});}
​function playerSong(obj) {var name = obj.substring(obj.lastIndexOf("=")+1);//obj:播放的音乐的地址  name:播放的音乐的名称,0:播放的开始时间  false:不自动播放SewisePlayer.toPlay(obj,name,0,true);}
​function deleteInfo(obj) {console.log(obj);$.ajax({url:"/music/delete",type: "POST",data:{"id":obj},dataType:"json",
​success: function(val) {console.log(val);
​if(val.data == true) {//删除成功!alert("删除成功!,重新加载当前页面!");window.location.href = "list.html";}else{alert("删除失败!");}}});}
​
​$(function(){$("#submit1").click( function(){var name = $("#exampleInputName2").val();load(name);});
​$.when(load).done(function(){$("#delete").click(function(){var id = new Array();var i = 0;//数组的小标//$("input:checkbox").each(function(){//如果被选中,this代表发生事件的dom元素,<input>if( $(this).is(":checked")) {id[i] = $(this).attr("id");i++;}});
​console.log(id);
​$.ajax({url:"/music/deleteSel",data:{"id":id},dataType:"json",type:"post",
​success:function(obj){if(obj.data == true) {alert("删除成功!");window.location.href = "list.html";}else{alert("删除失败!");}}});});});});
​
​function loveInfo(obj) {
​$.ajax({url:"/lovemusic/likeMusic",type:"POST",data:{"id":obj},dataType:"json",
​success:function(val){if(val.data == true) {alert("收藏成功!");window.location.href = "list.html";}else{alert("收藏失败!");}}});}
​
​</script>
</head>
​
<body id="body">
<div class="container"><h3  style="text-align: center">在线音乐服务器实现</h3><div style="float: left;"><form class="form-inline"><div class="form-group"><label for="exampleInputName2">歌曲名</label><input name="name" type="text" class="form-control" id="exampleInputName2" ></div><button id="submit1" type="button" class="btn btn-primary">查询</button></form></div><div style="float: right;margin-bottom: 15px"><a class="btn btn-primary" href="loveMusic.html">喜欢列表</a><a class="btn btn-primary" href="upload.html">添加歌曲</a><a id="delete" class="btn btn-primary">删除选中</a></div><table border="1" class="table table-bordered table-hover"><tr class="success"><th>选择</th><th>歌名</th><th>歌手</th><th>歌曲</th><th>操作</th></tr>
​​<tbody id="info" valign="middle"><tr><th> <input id="1" type="checkbox"> </th><td>成都</td><td>赵雷</td><td><button class="btn btn-primary" οnclick="playerSong('+musicUrl+')">播放歌曲</button></td><td><button class="btn btn-primary" οnclick="deleteInfo('+musicUrl+')">删除</button><button class="btn btn-primary" οnclick="loveInfo('+musicUrl+')">喜欢</button>  </td></tr><tr><th> <input id="2" type="checkbox"> </th><td>成都</td><td>赵雷</td><td><button class="btn btn-primary" οnclick="playerSong('+musicUrl+')">播放歌曲</button></td><td><button class="btn btn-primary" οnclick="deleteInfo('+musicUrl+')">删除</button><button class="btn btn-primary" οnclick="loveInfo('+musicUrl+')">喜欢</button>  </td></tr></tbody></table>
</div>
</body>
<div style="width: 180px; height: 140px; position:absolute; bottom:10px; right:10px"><script type="text/javascript" src="player/sewise.player.min.js"></script><script type="text/javascript">SewisePlayer.setup({server: "vod",type: "mp3",//这里是默认的一个网址videourl:"http://jackzhang1204.github.io/materials/where_did_time_go.mp3",skin: "vodWhite",//这里需要设置falseautostart:"false",});</script>
</div>
</html>
​

这里播放歌曲,我们采用开源的播放控件: 码云地址:sewise-player: Sewise Player是一款专业的免费网页HTML5视频、流播放器,它功能强大,体积小,跨平台,兼容性好,使用方便简洁、随心所欲。

将该开源项目,下载到本地,取出player文件夹,放入static文件夹下。 嵌入播放器: 实现播放

<div style="width: 180px; height: 140px; position:absolute;         bottom:10px; right:10px"><script type="text/javascript" src="player/sewise.player.min.js"></script><script type="text/javascript">SewisePlayer.setup({server: "vod",type: "mp3",//这里是默认的一个网址videourl:"http://jackzhang1204.github.io/materials/where_did_time_go.mp3",skin: "vodWhite",//这里需要设置falseautostart:"false",});
</script>
</div>function playerSong(obj) {
console.log(obj)
var name = obj.substring(obj.lastIndexOf('=')+1);
//obj:播放地址 name:歌曲或者视频名称
SewisePlayer.toPlay(obj,name,0,true);
}

4收藏页面

loveMusic.html

<!DOCTYPE html>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head><!-- 指定字符集 --><meta charset="utf-8"><!-- 使用Edge最新的浏览器的渲染方式 --><meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。width: 默认宽度与设备的宽度相同initial-scale: 初始的缩放比,为1:1 --><meta name="viewport" content="width=device-width, initial-scale=1"><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
​<title>在线音乐服务器实现</title>
​<link rel="shortcut icon" href="#" />
​<!-- 1. 导入CSS的全局样式 --><link href="css/bootstrap.min.css" rel="stylesheet"><!-- 2. jQuery导入,建议使用1.9以上的版本 --><script src="js/jquery-3.1.1.min.js"></script><!-- 3. 导入bootstrap的js文件 --><!-- <script src="js/bootstrap.min.js"></script>--><style type="text/css">td, th {text-align: center;}</style><script>
​// 核心代码实现$(function(){load();
​});
​//musicName可以传参  也可以不传参数function load(musicName) {$.ajax({url:"/lovemusic/findlovemusic",data:{"musicName": musicName},type:"GET",dataType:"json",success:function(obj) {console.log(obj);var data = obj.data;//数组var s = '';//data[i].id    data[i].singer  data[i].titlefor(var i = 0; i < data.length;i++) {var musicUrl = data[i].url+".mp3";console.log(musicUrl);s += '<tr>';s += '<td>'+data[i].title+'</td>';s += '<td>'+data[i].singer+'</td>';s += "<td <a href=\"\">  <audio src= \""+ musicUrl+"\"  + controls=\"controls\" preload=\"none\" loop=\"loop\">  >"  + "</audio> </a> </td>";//s += '<td> <button class = "btn btn-primary"  οnclick="playerSong(\''+musicUrl+'\')"> 播放歌曲 </button>' +'</td>';s += '<td> <button class = "btn btn-primary"  οnclick="deleteInfo('+data[i].id+')"> 移除 </button>'  +'</td>';s += "</tr>"}$("#info").html(s);}});}
​function playerSong(obj) {var name = obj.substring(obj.lastIndexOf("=")+1);//obj:播放的音乐的地址  name:播放的音乐的名称,0:播放的开始时间  false:不自动播放SewisePlayer.toPlay(obj,name,0,true);}
​function deleteInfo(obj) {console.log(obj);$.ajax({url:"/lovemusic/deletelovemusic",type: "POST",data:{"id":obj},dataType:"json",
​success: function(val) {console.log(val);
​if(val.data == true) {//删除成功!alert("删除成功!,重新加载当前页面!");window.location.href = "list.html";}else{alert("删除失败!");}}});}
​$(function(){$("#submit1").click( function(){var name = $("#exampleInputName2").val();load(name);});});
​
</script>
</head>
<body>
<div class="container"><h3 style="text-align: center">我喜欢的音乐列表</h3><div style="float: left;"><form class="form-inline"><div class="form-group"><label for="exampleInputName2">歌曲名</label><input name="name" type="text" class="form-control" id="exampleInputName2" ></div><button id="submit1" type="button" class="btn btn-default">查询</button></form></div><div style="float: right;margin-bottom: 15px"><a class="btn btn-primary" href="list.html">回到首页</a></div><table border="1" class="table table-bordered table-hover"><tr class="success"><th>歌名</th><th>歌手</th><th>歌曲</th><th>操作</th></tr><tbody id="info" valign="middle"><tr><td>成都</td><td>赵雷</td><td><button class="btn btn-primary" οnclick="playerSong('+musicUrl+')">播放歌曲</button></td><td><button class="btn btn-primary" οnclick="deleteInfo('+musicUrl+')">删除</button></td></tr>
​<tr><td>成都</td><td>赵雷</td><td><button class="btn btn-primary" οnclick="playerSong('+musicUrl+')">播放歌曲</button></td><td><button class="btn btn-primary" οnclick="deleteInfo('+musicUrl+')">删除</button></td></tr></tbody></table>
</div>
</body>
<div style="width: 180px; height: 140px; position:absolute; bottom:10px; right:10px"><script type="text/javascript" src="player/sewise.player.min.js"></script><script type="text/javascript">SewisePlayer.setup({server: "vod",type: "mp3",//这里是默认的一个网址videourl:"http://jackzhang1204.github.io/materials/where_did_time_go.mp3",skin: "vodWhite",//这里需要设置falseautostart:"false",});</script>
</div>
</html>
​

5配置拦截器

config包下修改AppConfig,创建LoginInterecptor

@Configuration
public class AppConfig {@Beanpublic BCryptPasswordEncoder getBCryptPasswordEncoder() {return new BCryptPasswordEncoder();}
​public void addInterceptors(InterceptorRegistry registry) {
//1、配置拦截规则LoginInterecptor loginInterceptor = new LoginInterecptor();registry.addInterceptor(loginInterceptor).addPathPatterns("/**")
//排除所有的JS.excludePathPatterns("/js/**.js")
//排除images下所有的元素.excludePathPatterns("/images/**").excludePathPatterns("/css/**.css").excludePathPatterns("/fronts/**").excludePathPatterns("/player/**").excludePathPatterns("/login.html")
//排除登录接口.excludePathPatterns("/user/login");}
}
public class LoginInterecptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {
​HttpSession httpSession = request.getSession(false);return httpSession != null && httpSession.getAttribute(Constant.USERINFO_SESSION_KEY) != null;}
}
​

小项目----音乐在线播放器相关推荐

  1. 独家首发DJ舞曲音乐在线播放微信小程序源码下载支持多分类歌曲

    这是一款音乐播放小程序源码 音乐内容是属于DJ,电音,舞曲等等这类型的 该小程序的歌曲有七大分类,分别是: 第一分类热门推荐 第二分类中文舞曲 第三分类英文舞曲 第四分类慢摇舞曲 第五分类舞曲串烧 第 ...

  2. Java和vue实现音乐播放器_vue实现的网易云音乐在线播放和下载功能案例

    本文实例讲述了vue实现的网易云音乐在线播放和下载功能.分享给大家供大家参考,具体如下: 效果如图: 完整代码: Document html, body { height: 100%; padding ...

  3. HTML5期末大作业:在线音乐播放器网站设计——html5全屏的音乐列表播放器页面源码 HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设

    HTML5期末大作业:在线音乐播放器网站设计--html5全屏的音乐列表播放器页面源码 HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设 ...

  4. html在线音频播放器实训总结,HTML5音乐列表播放器SMusic开发总结

    前段时间写过一篇介绍简单音乐播放器效果开发的博文<为你的博客添加简单的CSS3音乐播放器>,实现了单曲循环播放效果,这个效果也是我的博客首页一直有的效果,同时文中也介绍了一些简单的HTML ...

  5. 简单的音乐在线播放网页

    调用网易云提供的音乐接口,编写一个简易的音乐在线播放网页 一.功能实现: 1.通过在输入框输入要查询的文字,调用后台接口获取响应的数据,并把需要的数据渲染到左侧. 2.通过点击可以选中左侧播放栏的某一 ...

  6. 解决Chrome浏览器打开虾米音乐网页播放器时的排版问题

    2019独角兽企业重金招聘Python工程师标准>>> 几年了,虾米音乐网页播放器听音乐都有个纠结的地方,就是用Chrome浏览器打开时,排版会出错,表现为播放器右边一部分显示不出来 ...

  7. android第三方开源音频播放器,Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用...

     Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用 Android平台原生的SeekBar设计简单,然而,比如现在流行的一些音乐播放器的播放进度控制条,如果直接使 ...

  8. 基于机器学习的自动音乐生成播放器

    目录 详细设计说明书 1 1 引言 1 1.1 编写目的 1 1.2 背景 1 2. 此项目的任务提出者:西电软件工程课程组.西电软件开发小组 1 1.3 定义 2 1.4 参考资料 2 3 程序描述 ...

  9. 在线播放器 在网页中插入MediaPlayer 兼容IE和FF的代码调试

    <!– 在线播放器 在网页中插入MediaPlayer 兼容IE和FF的代码调试 Internet Explorer 和 Netscape 都支持 <embed> 元素,但它不是标准 ...

最新文章

  1. python字符串、列表和文件对象总结
  2. jQuery Alert Dialogs (Alert, Confirm, Prompt Replacements)(翻译)
  3. 用c语言编写黎曼积分计算pi,C语言实现黎曼和求定积分
  4. 数据事业部/数据项目/数据乐高
  5. Java中恒等条件判断:“equals”和“==”
  6. matlab取角马为什么减一,动物世界角马为什么不敢攻击狮子?
  7. unipapp 解决无法编译sass_如何解决Vue项目里面没有sassloader依赖包的问题
  8. mysql序列号发生器
  9. Angular Component 实现类,先执行字段初始化,再调用构造函数
  10. xxx钻石商城功能开发需求
  11. C4D立体风格海报素材|电商万能套用BANNER是美工必收藏
  12. oracle组合索引最左原则,复合索引最左原则 -- 实战
  13. 制作单机俄罗斯方块游戏心得(二)
  14. Android中获取IMEI码及其它相关信息的源码
  15. 从线报群看短链接技术
  16. HTML里css画蝴蝶,纯css3制作煽动翅膀的蝴蝶的示例
  17. 【百度OCR 文字识别篇】好奇怪的SDK108错误,换种方法解决
  18. 百度地图获取经纬度后,获取区域代码和地址
  19. Nginx+Lua+Redis实现广告缓存
  20. 如何避免音频爆音/杂响?音频爆音常见的解决办法

热门文章

  1. linux 解决wps文档显示异常问题
  2. 求和计算机教案,七年级信息技术《Excel求和》教学设计
  3. 古天乐一哭,电影宣传又跪了下来
  4. 【机器学习】补完计划
  5. 新手卖家注意,提高转化率是关键
  6. PLC 定时器指令计数器指令比较赋值指令的总结
  7. thinkadmin按配置上传文件至本地,七牛云或阿里oss
  8. 亚马逊账号被关联能申诉得回来吗
  9. 网站PV、UV的含义
  10. python100day - day24 - DataAnalysis