小项目----音乐在线播放器
目录
音乐播放器
项目功能:
项目框架:
项目的创建很重要:
数据库设计
在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>×</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;} }
小项目----音乐在线播放器相关推荐
- 独家首发DJ舞曲音乐在线播放微信小程序源码下载支持多分类歌曲
这是一款音乐播放小程序源码 音乐内容是属于DJ,电音,舞曲等等这类型的 该小程序的歌曲有七大分类,分别是: 第一分类热门推荐 第二分类中文舞曲 第三分类英文舞曲 第四分类慢摇舞曲 第五分类舞曲串烧 第 ...
- Java和vue实现音乐播放器_vue实现的网易云音乐在线播放和下载功能案例
本文实例讲述了vue实现的网易云音乐在线播放和下载功能.分享给大家供大家参考,具体如下: 效果如图: 完整代码: Document html, body { height: 100%; padding ...
- HTML5期末大作业:在线音乐播放器网站设计——html5全屏的音乐列表播放器页面源码 HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设
HTML5期末大作业:在线音乐播放器网站设计--html5全屏的音乐列表播放器页面源码 HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设 ...
- html在线音频播放器实训总结,HTML5音乐列表播放器SMusic开发总结
前段时间写过一篇介绍简单音乐播放器效果开发的博文<为你的博客添加简单的CSS3音乐播放器>,实现了单曲循环播放效果,这个效果也是我的博客首页一直有的效果,同时文中也介绍了一些简单的HTML ...
- 简单的音乐在线播放网页
调用网易云提供的音乐接口,编写一个简易的音乐在线播放网页 一.功能实现: 1.通过在输入框输入要查询的文字,调用后台接口获取响应的数据,并把需要的数据渲染到左侧. 2.通过点击可以选中左侧播放栏的某一 ...
- 解决Chrome浏览器打开虾米音乐网页播放器时的排版问题
2019独角兽企业重金招聘Python工程师标准>>> 几年了,虾米音乐网页播放器听音乐都有个纠结的地方,就是用Chrome浏览器打开时,排版会出错,表现为播放器右边一部分显示不出来 ...
- android第三方开源音频播放器,Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用...
Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用 Android平台原生的SeekBar设计简单,然而,比如现在流行的一些音乐播放器的播放进度控制条,如果直接使 ...
- 基于机器学习的自动音乐生成播放器
目录 详细设计说明书 1 1 引言 1 1.1 编写目的 1 1.2 背景 1 2. 此项目的任务提出者:西电软件工程课程组.西电软件开发小组 1 1.3 定义 2 1.4 参考资料 2 3 程序描述 ...
- 在线播放器 在网页中插入MediaPlayer 兼容IE和FF的代码调试
<!– 在线播放器 在网页中插入MediaPlayer 兼容IE和FF的代码调试 Internet Explorer 和 Netscape 都支持 <embed> 元素,但它不是标准 ...
最新文章
- python字符串、列表和文件对象总结
- jQuery Alert Dialogs (Alert, Confirm, Prompt Replacements)(翻译)
- 用c语言编写黎曼积分计算pi,C语言实现黎曼和求定积分
- 数据事业部/数据项目/数据乐高
- Java中恒等条件判断:“equals”和“==”
- matlab取角马为什么减一,动物世界角马为什么不敢攻击狮子?
- unipapp 解决无法编译sass_如何解决Vue项目里面没有sassloader依赖包的问题
- mysql序列号发生器
- Angular Component 实现类,先执行字段初始化,再调用构造函数
- xxx钻石商城功能开发需求
- C4D立体风格海报素材|电商万能套用BANNER是美工必收藏
- oracle组合索引最左原则,复合索引最左原则 -- 实战
- 制作单机俄罗斯方块游戏心得(二)
- Android中获取IMEI码及其它相关信息的源码
- 从线报群看短链接技术
- HTML里css画蝴蝶,纯css3制作煽动翅膀的蝴蝶的示例
- 【百度OCR 文字识别篇】好奇怪的SDK108错误,换种方法解决
- 百度地图获取经纬度后,获取区域代码和地址
- Nginx+Lua+Redis实现广告缓存
- 如何避免音频爆音/杂响?音频爆音常见的解决办法