0
点赞
收藏
分享

微信扫一扫

基于 SpringBoot + MyBatis 的在线音乐播放器

崭新的韭菜 2022-07-31 阅读 107

文章目录

1. 项目设计

前端 : HTML+CSS+JavaScript+JQuery
后端 : Spring MVC+Spring Boot+MyBatis

在这里插入图片描述

2. 效果展示


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

3. 创建项目 配置文件

3.1 创建项目

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.2 配置文件

3.2.1 在 application.properties 中添加配置文件

配置数据库

spring.datasource.url=jdbc:mysql://localhost:3306/onlinemusicserver?characterEncoding=utf8true
spring.datasource.username=root
spring.datasource.password=0000
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

配置 Mybatis

mybatis.mapper-locations=classpath:mapper/**Mapper.xml

配置文件上传大小

spring.servlet.multipart.max-file-size = 15MB
spring.servlet.multipart.max-request-size=100MB

配置上传的路径

upload.path=E:/logs/

3.2.2 在 resources 目录下创建mapper

mapper下添加 目录 **.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.onlinemusicserver.mapper."对应的Mapper"">

</mapper>

4. 数据库的设计与实现

这里设计数据库.

在这里插入图片描述

drop database if exists `onlinemusicserver`;
create database `onlinemusicserver`;

use `onlinemusicserver`;

drop table if exists `user`;
create table `user`(
    `userId` int primary key auto_increment,
    `username` varchar(20) unique,
    `password` varchar(255) not null
);

drop table if exists `music`;
create table `music`(
    `musicId` int primary key auto_increment,
    `title` varchar(100) not null,
    `author` varchar(20) not null,
    `uploadtime` timestamp default CURRENT_TIMESTAMP,
    `path` varchar(1000) not null,
    `userId` int not null
);

drop table if exists `collect`;
create table `collect`(
    `collectId` int primary key auto_increment,
    `userId` int not null,
    `musicId` int not null
);

5. 交互接口的设计

在这里插入图片描述

请求
POST /music/upload HTTP/1.1

{singer, MultipartFile file}

响应
{
status: 1/-1 (1 为成功, -1 为失败),
message: "对应信息",
data: "内容"
}
请求
POST /collect/loveMusic HTTP/1.1

{musicId: 1}

响应
{
status: 1/-1,
message: "",
data: ""
}
请求
POST /collect/deleteLoveMusic HTTP/1.1

{musicId: 1}

响应
{
status: 1/-1,
message: "",
data: ""
}
请求
POST /collect/findLoveMusic HTTP/1.1

{musicName: "可以为空可以不为空, 为空的时候,查询所有, 不为空的时候, 模糊查询"}

响应
{
status: 1/-1,
message: "",
data: {
{
musicId: "",
title: "",
author: "",
uploadtime: "",
path: "",
userId: "",
}
...
}
}
请求
POST /music/findMusic HTTP/1.1

{musicName: "可以为空可以不为空, 为空的时候,查询所有, 不为空的时候, 模糊查询"}

响应
{
status: 1/-1,
message: "",
data: {
{
musicId: "",
title: "",
author: "",
uploadtime: "",
path: "",
userId: "",
}
...
}
}
请求
POST /music/delete HTTP/1.1

{musicId: ""}

响应
{
status: 1/-1,
message: "",
data: ""
}
请求
POST /music/deleteMore HTTP/1.1

{musicId: "1 2 3 4 5"(数组)}

响应
{
status: 1/-1,
message: "",
data: ""
}
请求
GET /music/play?path="..." HTTP/1.1

响应
{
音乐的字节信息
}
请求
POST /user/login HTTP/1.1

{username: "",password: ""}

响应
{
status: 1/-1,
message: "",
data: ""
}
请求
GET /user/logout HTTP/1.1

响应
HTTP/1.1 200
请求
POST /user/register HTTP/1.1

{username: "",password: ""}

响应
{
status: 1/-1,
message: "",
data: ""
}

6. 工具包

6.1 设置统一响应类

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;
    }
}

6.2 Constant类

public class Constant {
    public static final String USER_SESSION_KEY = "user";
}

6.3 了解 MD5 加密 和 BCrypt 加密

MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆; 但是虽然不可逆,但是不是说就是安全的。因为自从出现彩虹表后,这样的密码也"不安全"。

更安全的做法是加盐或者长密码等做法,让整个加密的字符串变的更长,破解时间变慢。

Bcrypt就是一款加密工具,可以比较方便地实现数据的加密工作。你也可以简单理解为它内部自己实现了随机加盐处理 。我们使用MD5加密,每次加密后的密文其实都是一样的,这样就方便了MD5通过大数据的方式进行破解。
Bcrypt生成的密文是60位的。而MD5的是32位的。Bcrypt破解难度更大。

MD5使用示例 (加盐)

添加依赖

<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>

实现类


public class MD5Util {
    private static final String salt = "1q2w3e4r5t";//可任意设置

    public static String md5(String src) {
        return DigestUtils.md5Hex(src);
    }

    /**
     * 第一次加密 :模拟前端自己加密,然后传到后端
     * @param inputPass
     * @return
     */
    public static String inputPassToFormPass(String inputPass) {
        String str = ""+salt.charAt(1)+salt.charAt(3) + inputPass
                +salt.charAt(5) + salt.charAt(6);
        return md5(str);
    }

    /**
     * 第二次加密
     * @param formPass 前端加密过的密码,传给后端进行第2次加密
     * @param salt 后端当中的盐值
     * @return
     */
    public static String formPassToDBPass(String formPass, String salt) {
        String str = ""+salt.charAt(0)+salt.charAt(2) + formPass +salt.charAt(5)
                + salt.charAt(4);
        return md5(str);
    }

    /**
     * 上面两个函数合到一起进行调用
     * @param inputPass
     * @param saltDB
     * @return
     */
    public static String inputPassToDbPass(String inputPass, String saltDB) {
        String formPass = inputPassToFormPass(inputPass);
        String dbPass = formPassToDBPass(formPass, saltDB);
        return dbPass;
    }
}

在这里插入图片描述

BCrypt使用示例

添加依赖

<!-- 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>

在springboot启动类添加:

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

创建BCryptTest测试类:

public class BCryptTest {
public static void main(String[] args) {
    //模拟从前端获得的密码
    String password = "123456";
    BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
    String newPassword = bCryptPasswordEncoder.encode(password);
    System.out.println("加密的密码为: "+newPassword);
    //使用matches方法进行密码的校验
    boolean same_password_result = bCryptPasswordEncoder.matches(password,newPassword);
    //返回true
    System.out.println("加密的密码和正确密码对比结果: "+same_password_result);
    boolean other_password_result = bCryptPasswordEncoder.matches("987654",newPassword);
    //返回false
    System.out.println("加密的密码和错误的密码对比结果: " + other_password_result);
}

运行结果: (每次加密的密码都不同)
在这里插入图片描述
在这里插入图片描述

6.4 在Config中 注入 BCryptPasswordEncoder 对象

@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Bean
    public BCryptPasswordEncoder getBCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

6.5 添加拦截器

6.5.1 LoginInterceptor 类

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession httpSession = request.getSession(false);
        if(httpSession != null && httpSession.getAttribute(Constant.USER_SESSION_KEY) != null) {
            return true;
        }
        response.sendRedirect("/login.html");
        return false;
    }
}

6.5.2 AppConfig 类

@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        LoginInterceptor loginInterceptor = new LoginInterceptor();
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/**/login.html")
                .excludePathPatterns("/**/css/**.css")
                .excludePathPatterns("/**/images/**")
                .excludePathPatterns("/**/fonts/**")
                .excludePathPatterns("/**/js/**.js")
                .excludePathPatterns("/**/scss/**")
                .excludePathPatterns("/**/user/login")
                .excludePathPatterns("/**/user/register")
                .excludePathPatterns("/**/user/logout");
    }
}

7. 登录模块

7.1 创建 User 实体类

@Data
public class User {
    private int userId;
    private String username;
    private String password;
}

7.2 使用 Mybatis 操作数据库

7.2.1 在 UserServer 中添加代码

public User selectByName(String username) {
        return userMapper.selectByName(username);
    }

7.2.2 在 UserMapper 中添加代码

    /**
     * 通过用户名去查找用户信息, 用来对比登录信息.
     * @param username 用户名
     * @return 对应用户名的用户信息
     */
    User selectByName(String username);

7.2.3 在 UserMapper.xml 中添加代码

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

7.3 创建 UserConroller 添加代码

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserServer userServer;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    /**
     * 用户登录
     * @param user
     * @param req
     * @return
     */
    @RequestMapping("/login")
    public ResponseBodyMessage<User> login(@RequestBody User user, HttpServletRequest req) {
        User truUser = userServer.selectByName(user.getUsername());
        if(truUser != null) {
            System.out.println("登陆成功");
            System.out.println(user.getPassword() + " " + truUser.getPassword());
            boolean flg = bCryptPasswordEncoder.matches(user.getPassword(),truUser.getPassword());
            if(!flg) {
                return new ResponseBodyMessage<>(-1,"当前账号密码错误!",user);
            }
            HttpSession session = req.getSession(true);
            session.setAttribute(Constant.USER_SESSION_KEY,truUser);
            return new ResponseBodyMessage<>(1,"登录成功!",truUser);
        }else{
            System.out.println("登录失败");
            return new ResponseBodyMessage<>(-1,"当前账号密码错误!",user);
        }
    }
}

7.4 前端代码

let loginButton = document.querySelector('#loginButton');
		loginButton.onclick = function() {
			let username = document.querySelector('#loginUsername');
			let password = document.querySelector('#loginPassword');
			if (username.value.trim() == ""){
                alert('请先输入用户名!');
                username.focus();
                return;
            }
            if (password.value.trim() == ""){
                alert('请先输入密码!');
                password.focus();
                return;
            }
            $.ajax({
                url: "user/login",
                method: "POST",
                data: JSON.stringify({username: username.value.trim(), password: password.value.trim()}),
                contentType: "application/json;charset=utf-8",
                success: function(data, status) {
                    if(data.status == 1) {
                        location.assign("index.html");
                    }else{
                        alert(data.message);
                        username.value="";
                        password.value="";
                        username.focus();
                    }
                }
			})
		}

8. 注册模块

8.1 使用 Mybatis 操作数据库

8.1.1 在 UserServer 中添加代码

 public int addnewUser(User newUser) {
        return userMapper.addnewUser(newUser);
    }

8.1.2 在 UserMapper 中添加代码

    /**
     * 注册新的用户
     * @param newUser 新用户信息
     * @return
     */
    int addnewUser(User newUser);

8.1.3 在 UserMapper.xml 中添加代码

    <insert id="addnewUser">
        insert into user(username,password) values (#{username},#{password});
    </insert>

8.2 向 UserController 中添加代码

	/**
     * 注册用户
     * @param user 用户信息
     * @return 
     */
    @RequestMapping("/register")
    public ResponseBodyMessage<Boolean> register(@RequestBody User user) {
        User user1 = userServer.selectByName(user.getUsername());
        if(user1 != null) {
            return new ResponseBodyMessage<>(-1,"当前用户已经存在",false);
        }else {
            User newUser = new User();
            newUser.setUsername(user.getUsername());
            String newPassword = bCryptPasswordEncoder.encode(user.getPassword());
            newUser.setPassword(newPassword);
            userServer.addnewUser(newUser);
            return new ResponseBodyMessage<>(1,"注册成功",true);
        }
    }

8.3 前端代码

在这里插入图片描述

let Reg = document.querySelector('#Reg');
		Reg.onclick = function() {
			let username = document.querySelector('#RegUsername');
			let password1 = document.querySelector('#RegPassword1');
			let password2 = document.querySelector('#RegPassword2');
			if(!$('#checkbox').is(':checked')) {
				alert("请勾选条款");
				return;
			}
			if(username.value.trim() == ""){
                alert("请先输入用户名!");
                username.focus();
                return;
            }
            if(password1.value.trim() == ""){
                alert('请先输入密码!');
                password1.focus();
                return;
            }
            if(password2.value.trim() == ""){
                alert('请再次输入密码!');
                password2.focus();
                return;
            }
            if(password1.value.trim() != password2.value.trim()) {
                alert('两次输入的密码不同!');
                passwrod1.value="";
                password2.value="";
                return;
            }
			$.ajax({
                url: "user/register",
                method: "POST",
                data: JSON.stringify({username: username.value.trim(), password: password1.value.trim()}),
                contentType: "application/json;charset=utf-8",
                success: function(data,status){
                    if(data.status == 1) {
						alert(data.message);
						location.assign("login.html");
					}else{
						alert(data.message);
						username.value="";
                        password1.value="";
                        password2.value="";
                        username.focus();
					}
                }
            })
		}

9. 退出功能

9.1 向 UserController 中添加代码

    @RequestMapping("/logout")
    public void userLogout(HttpServletRequest request, HttpServletResponse response) throws IOException {
        HttpSession session = request.getSession(false);
        // 拦截器的拦截, 所以不可能出现session为空的情况
        session.removeAttribute(Constant.USER_SESSION_KEY);
        response.sendRedirect("login.html");
    }

9.2 登录注册测试.

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

10. 上传音乐模块

10.1 创建 Music 实体类

@Data
public class Music {
    private int musicId;
    private String title;
    private String author;
    private Timestamp uploadtime;
    private String path;
    private int userId;
    private String srcPath;
}

10.2 使用 Mybatis 操作数据库

10.2.1 在 MusicServer 中添加代码

    public int insert(String title, String author, String path, int userId){
        return musicMapper.insert(title,author,path,userId);
    }
	public List<Music> selectByTitle(String title) {
        return musicMapper.selectByTitle(title);
    }

10.2.2 在 MusicMapper 中添加代码

    /**
     * 上传音乐
     * @param title 音乐名
     * @param author 歌手
     * @param path 对应的地址
     * @param userId 上传的用户Id
     * @return 返回影响行数
     */
    int insert(String title, String author, String path, int userId);

	/**
     * 通过音乐名去查找歌曲.
     * @param title 音乐名
     * @return 对应音乐名的所有歌曲
     */
    List<Music> selectByTitle(String title);

10.2.3 在 MusicMapper.xml 中添加代码

<insert id="insert">
    insert into music(title,author,path,userId) values (#{title},#{author},#{path},#{userId});
</insert>

<select id="selectByTitle" resultType="com.example.onlinemusicserver.model.Music">
    select * from music where title = #{title};
</select>

10.3 向 MusicController 中添加代码


@RestController
@RequestMapping("/music")
public class MusicController {
    @Autowired
    private MusicServer musicServer;

    @Value("${upload.path}")
    public String SAVE_PATH;

    /**
     * 上传音乐
     * @param singer
     * @param file
     * @param request
     * @return
     */
    @RequestMapping("/upload")
    public ResponseBodyMessage<Boolean> insertMusic(@RequestParam String singer,
                                                    @RequestPart("filename") MultipartFile file,
                                                    HttpServletRequest request,
                                                    HttpServletResponse response) {
        // 检测登录
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute(Constant.USER_SESSION_KEY) == null) {
            System.out.println("当前未登录!");
            return new ResponseBodyMessage<>(-1,"请登录后上传",false);
        }

        // 文件的类型
        String fileNameAndType = file.getOriginalFilename();

        // 防止出现重复的相同歌曲和相同歌手.可以出现相同歌曲不同歌手
        String title = fileNameAndType.substring(0,fileNameAndType.lastIndexOf('.'));
        // 可能出现多首名称相同的歌曲, 所以用 List
        List<Music> list = musicServer.selectByTitle(title);
        if(list != null){
            for(Music music : list) {
                if(music.getAuthor().equals(singer)){
                    return new ResponseBodyMessage<>(-1,"当前歌手的歌曲已经存在!",false);
                }
            }
        }

        // 创建文件
        String path = SAVE_PATH +singer+"-"+fileNameAndType;

        File dest = new File(path);
        if(!dest.exists()) {
            dest.mkdirs();
        }

        try {
            file.transferTo(dest);
            //return new ResponseBodyMessage<>(1,"上传成功!",true);
        } catch (IOException e) {
            e.printStackTrace();
            return new ResponseBodyMessage<>(-1,"服务器上传失败!",false);
        }

        // 这里对是不是 MP3 文件进行判断. 主要是判断是否存在 TAG 这个字符
        File file1 = new File(path);
        byte[] res = null;
        try {
            res = Files.readAllBytes(file1.toPath());
            if(res == null) {
                return new ResponseBodyMessage<>(-1,"当前文件不存在",false);
            }
            String str = new String(res);
            if(!str.contains("TAG")) {
                file1.delete();
                return new ResponseBodyMessage<>(-1,"当前不是mp3文件",false);
            }
        }catch (IOException e){
            e.printStackTrace();
            return new ResponseBodyMessage<>(-1,"服务器出现问题", false);
        }

        // 在数据库中上传数据
        User user = (User) session.getAttribute(Constant.USER_SESSION_KEY);
        // 这里传递的 path 没有带 `.MP3` 后期在前端进行设置
        String uploadPath = "/music/play?path="+singer+"-"+title;
        try {
            int ret = musicServer.insert(title,singer,uploadPath,user.getUserId());
            if(ret == 1) {
                response.sendRedirect("/index.html");
                return new ResponseBodyMessage<>(1,"上传成功",true);
            }else {
                return new ResponseBodyMessage<>(-1,"数据库上传失败",false);
            }
        }catch (BindingException | IOException e) {
            dest.delete();
            return new ResponseBodyMessage<>(-1,"数据库上传失败",false);
        }
    }
}

10.4 前端代码

<form method="post" enctype="multipart/form-data" action="music/upload">
    文件上传: <input type="file" name="filename" id="filename" />
    歌手名: <label>
    <input type="text" name="singer" placeholder="请输入歌手名" id="singer" /> 
    </label>
    <input type="submit" value="上传" id="submit"/>
</form>

10.5 测试代码

在这里插入图片描述

11. 播放音乐模块

11.1 向 MusicController 中添加代码

    /**
     * 播放音乐
     * @param path
     * @return
     */
    @RequestMapping("/play")
    public ResponseEntity<byte[]> playMusic(@RequestParam String path){
        File file = new File(SAVE_PATH + path);
        byte[] res = null;
        try {
            res = Files.readAllBytes(file.toPath());
            if (res == null) {
                return ResponseEntity.badRequest().build();
            }
            return ResponseEntity.ok(res);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.badRequest().build();
        }
    }

11.2 测试代码

在这里插入图片描述

观察字节码可以看出, 有 TAG 这个字符

在这里插入图片描述

12. 删除音乐模块

12.1 使用 Mybatis 操作数据库

12.1.1 在 MusicServer 和 CollectServer 中添加代码

musicServer

	public Music selectById(int musicId) {
        return musicMapper.selectById(musicId);
    }

    public int deleteById(int musicId) {
        return musicMapper.deleteById(musicId);
    }

collectServer

	public int deleteLoveMusicById(int musicId){
        return collectMapper.deleteLoveMusicById(musicId);
    }

12.1.2 在 MusicMapper 和 CollectMapper 中添加代码

musicMapper

 	/**
     * 通过音乐Id去查找歌曲
     * @param musicId 音乐Id
     * @return 查找到的音乐Id
     */
    Music selectById(int musicId);

    /**
     * 删除对应音乐Id的歌曲
     * @param musicId 音乐Id
     * @return 返回影响行数
     */
    int deleteById(int musicId);

collectMapper

    /**
     * 删除收藏表中音乐Id为musicId的
     * @param musicId 音乐Id
     * @return 返回受影响行数
     */
    int deleteLoveMusicById(int musicId);

12.1.3 在 MusicMapper.xml 和 CollectMapper.xml 中添加代码

MusicMapper.xml

	<select id="selectById" resultType="com.example.onlinemusicserver.model.Music">
        select * from music where musicId = #{musicId};
    </select>

    <delete id="deleteById">
        delete from music where musicId = #{musicId};
    </delete>

CollectMapper.xml

    <delete id="deleteLoveMusicById">
        delete from collect where musicId = #{musicId};
    </delete>

12.2 删除单一音乐功能

12.2.1 向 MusicController 中添加代码

    /**
     * 删除音乐
     * @param musicId
     * @return
     */
    @RequestMapping("/delete")
    public ResponseBodyMessage<Boolean> deleteMusic(@RequestParam String musicId) {
        // 1. 检测音乐是不是存在
        Music music = musicServer.selectById(Integer.parseInt(musicId));
        // 2. 不存在直接返回, 存在就删除
        if (music == null) {
            System.out.println("该音乐不存在");
            return new ResponseBodyMessage<>(-1,"没有你要删除的音乐",false);
        }
        // 2.1 删除数据库中的记录
        int ret = musicServer.deleteById(Integer.parseInt(musicId));
        if(ret == 1) {
            // 2.2 删除服务器上的数据
            int index = music.getPath().lastIndexOf("=");
            String PathName = music.getPath().substring(index+1);
            File file = new File(SAVE_PATH + PathName+".mp3");
            if(file.delete()){
                collectServer.deleteLoveMusicById(Integer.parseInt(musicId));
                return new ResponseBodyMessage<>(1,"删除成功!",true);
            }else{
                return new ResponseBodyMessage<>(-1,"服务器删除失败!",false);
            }
        }else {
            return new ResponseBodyMessage<>(-1,"数据库删除失败!",false);
        }
    }

12.2.2 前端代码

		function deleteMusic(musicId) {
          $.ajax({
            url: "music/delete",
            method: "post",
            data:{"musicId":musicId},
            dataType: "json",
            success:function(data,status) {
              if(data.status == 1) {
                alert(data.message);
                location.assign("index.html");
              }else{
                alert(data.message);
              }
            }
          })
        }

12.2.3 测试代码

在这里插入图片描述

12.3 删除多个音乐功能

12.3.1 向 MusicConroller 中添加代码

    /**
     * 删除多选音乐
     * @param musicId
     * @return
     */
    @RequestMapping("/deleteMore")
    public ResponseBodyMessage<Boolean> deleteMoreMusic(@RequestParam("musicId[]") List<Integer> musicId) {
        int sum = 0;
        for (int i = 0; i < musicId.size(); i++) {
            Music music = musicServer.selectById(musicId.get(i));
            if(music == null) {
                return new ResponseBodyMessage<>(-1,"没有你要删除的音乐",false);
            }
            int ret = musicServer.deleteById(musicId.get(i));
            if (ret == 1) {
                int index = music.getPath().lastIndexOf("=");
                String PathName = music.getPath().substring(index+1);
                File file = new File(SAVE_PATH + PathName+".mp3");
                if(file.delete()){
                    collectServer.deleteLoveMusicById(musicId.get(i));
                    sum += ret;
                }else{
                    return new ResponseBodyMessage<>(-1,"服务器删除失败!",false);
                }
            }else {
                return new ResponseBodyMessage<>(-1,"数据库删除失败!",false);
            }
        }
        if(sum == musicId.size()) {
            return new ResponseBodyMessage<>(1,"音乐删除成功!",true);
        }else{
            return new ResponseBodyMessage<>(-1,"音乐删除失败!",false);
        }
    }

12.3.2 前端代码

$(function(){
      $.when(load).done(function() {
        $("#deleteMore").click(function(){
          let musicId = new Array();
          let i =0;
          $("input:checkbox").each(function(){
            if($(this).is(":checked")) {
              musicId[i] = $(this).attr("id");
              i++;
            }
          });

          $.ajax({
            url: "music/deleteMore",
            method: "post",
            data:{"musicId":musicId},
            dataType:"json",
            success:function(data,status) {
              if(data.status == 1) {
                alert(data.message);
                location.assign("index.html");
              }else{
                alert(data.message);
              }
            }
          })
        })
      })
    })

12.3.3 测试代码

在这里插入图片描述

13. 收藏音乐模块

13.1 创建 Collect 实体类

@Data
public class Collect {
    private int collectId;
    private int userId;
    private int musicId;
}

13.2 使用 Mybatis 操作数据库

13.2.1 在 CollectServer 中添加代码

	public Collect findCollectMusic(int userId, int musicId) {
        return collectMapper.findCollectMusic(userId,musicId);
    }

	public int insertLoveMusic(int userId, int musicId) {
        return collectMapper.insertLoveMusic(userId, musicId);
    }

13.2.2 在 CollectMapper 中添加代码

        /**
     * 查看对应用户是否已经收藏了该音乐
     * @param userId 用户Id
     * @param musicId 音乐Id
     * @return 收藏歌单
     */
    Collect findCollectMusic(int userId, int musicId);

	/**
     * 收藏音乐
     * @param userId 用户Id
     * @param musicId 音乐Id
     * @return 返回影响行数
     */
    int insertLoveMusic(int userId, int musicId);

13.2.3 在 CollectMapper.xml 中添加代码

    <select id="findCollectMusic" resultType="com.example.onlinemusicserver.model.Collect">
        select * from collect where userId = #{userId} and musicId = #{musicId};
    </select>

	<insert id="insertLoveMusic">
        insert into collect(userId,musicId) values(#{userId},#{musicId});
    </insert>

13.3 向 CollectControll 中添加代码

/**
 * 点击收藏的时候, 收藏音乐
 * @param musicId
 * @param request
 * @return
 */
@RequestMapping("/loveMusic")
public ResponseBodyMessage<Boolean> AddLoveMusic(@RequestParam String musicId, HttpServletRequest request) {
    int music_Id = Integer.parseInt(musicId);
    HttpSession session = request.getSession(false);
    User user = (User) session.getAttribute(Constant.USER_SESSION_KEY);
    int userId = user.getUserId();

    Collect collect = collectServer.findCollectMusic(userId,music_Id);
    if (collect != null) {
        return new ResponseBodyMessage<>(-1, "当前已经收藏了",false);
    }else{
        int ret = collectServer.insertLoveMusic(userId,music_Id);
        if(ret == 1) {
            return new ResponseBodyMessage<>(1, "收藏成功!",true);
        }else{
            return new ResponseBodyMessage<>(-1,"收藏失败",false);
        }
    }
}

13.4 前端代码

function collectMusic(musicId) {
          $.ajax({
            url: "collect/loveMusic",
            method: "post",
            data:{"musicId":musicId},
            dataType: "json",
            success:function(data,status){
              if(data.status == 1) {
                alert(data.message);
                location.assign("collect.html");
              }else{
                alert(data.message);
              }
            }
          })
}

13.5 测试代码

在这里插入图片描述

14. 取消收藏音乐模块

14.1 使用 Mybatis 操作数据库

14.1.1 在 CollectServer 中添加代码

    public int deleteLoveMusic(int userId,int musicId){
        return collectMapper.deleteLoveMusic(userId,musicId);
    }

14.1.2 在 CollectMapper 中添加代码

     /**
     * 删除用户收藏的对应的音乐Id
     * @param userId 用户Id
     * @param musicId 音乐Id
     * @return 受影响行数
     */
    int deleteLoveMusic(int userId,int musicId);

14.1.3 在 CollectMapper.xml 中添加代码

    <delete id="deleteLoveMusic">
        delete from collect where userId = #{userId} and musicId = #{musicId}
    </delete>

14.2 向 CollectControll 中添加代码

    /**
     * 删除收藏的音乐
     * @param musicId
     * @param request
     * @return
     */
    @RequestMapping("/deleteLoveMusic")
    public ResponseBodyMessage<Boolean> deleteLoveMusic(@RequestParam String musicId,HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if(session == null) {
            return new ResponseBodyMessage<>(-1,"当前未登录",false);
        }
        User user = (User) session.getAttribute(Constant.USER_SESSION_KEY);
        int userId = user.getUserId();

        int ret =  collectServer.deleteLoveMusic(userId,Integer.parseInt(musicId));
        if(ret == 1) {
            return new ResponseBodyMessage<>(1,"取消收藏成功!",true);
        }else{
            return new ResponseBodyMessage<>(-1,"取消收藏失败!",false);
        }
    }

14.3 前端代码

		function deleteLoveMusic(musicId) {
          $.ajax({
            url: "collect/deleteLoveMusic",
            method: "post",
            data:{"musicId":musicId},
            dataType: "json",
            success:function(data,status) {
              if(data.status == 1) {
                alert(data.message);
                location.assign("collect.html");
              }else{
                alert(data.message);
              }
            }
          })
        }

14.4 测试代码

在这里插入图片描述

15. 主页面 - 查询模块

15.1 使用 Mybatis 操作数据库

15.1.1 在 MusicServer 中添加代码

	public List<Music> findMusic() {
        return musicMapper.findMusic();
    }

    public List<Music> findMusicByName(String name) {
        return musicMapper.findMusicByName(name);
    }

15.1.2 在 MusicMapper 中添加代码

	/**
     * 查找所有的歌曲
     * @return 所有的歌曲
     */
    List<Music> findMusic();

    /**
     * 支持模糊查询的歌曲.
     * @param name 部分歌曲名
     * @return 对应所有的歌曲
     */
    List<Music> findMusicByName(String name);

15.1.3 在 MusicMapper.xml 中添加代码

    <select id="findMusic" resultType="com.example.onlinemusicserver.model.Music">
        select * from music;
    </select>

    <select id="findMusicByName" resultType="com.example.onlinemusicserver.model.Music">
        select * from music where title like concat('%',#{name},'%');
    </select>

15.2 向 MusicController 中添加代码

    /**
     * 支持模糊查询, 支持空查询
     * @param name
     * @return
     */
    @RequestMapping("/findMusic")
    public ResponseBodyMessage<List<Music>> findMusic(@RequestParam(required = false) String name) {
        List<Music> list = null;
        if(name != null) {
            list = musicServer.findMusicByName(name);
        }else {
            list = musicServer.findMusic();
        }
        return new ResponseBodyMessage<>(1,"查询完毕!",list);
    }

15.3 前端代码

	  $(function(){load()});

      function load(musicName) {
        $.ajax({
          url: 'music/findMusic',
          method: 'POST',
          data: {"name":musicName},
          dataType: "json",
          success: function(data,status) {
            if(data.data!=null){
              createMusic1(data.data);
            let audios = document.querySelectorAll('#player2');
            for(let audio of audios) {
              new MediaElementPlayer(audio, {
                            pluginPath: 'https://cdn.jsdelivr.net/npm/mediaelement@4.2.7/build/',
                            shimScriptAccess: 'always',
                            success: function () {
                              let play = document.querySelector('.player');
                              play.style = "visibility: visible;";
                            }
              });
            }
            }
          }
        })
      }

      function createMusic1(lists) {
        let s = '';
        for(let list of lists) {
            s+= '<div class="d-block d-md-flex podcast-entry bg-white mb-5" data-aos="fade-up">';
            s+= '<img src="images/img_2.jpg" class="image">';
            s+= '<div class="text">';
            s+= '<input id="'+list.musicId+'" type="checkbox" class="checkbox">';
            s+= '<h3 class="font-weight-light">'+list.title+'</h3>';
            s+= '<div class="text-white mb-3"><span class="text-black-opacity-05"><small>'+list.author+'</small><span class="sep">/</span><small>'+DateFormat(list.uploadtime)+'</small></span></div>';
            s+= '<input type="button" class="btn btn-primary" style="margin: 5px;" value="收藏音乐" οnclick="collectMusic(\''+list.musicId+'\')">';
            s+= '<input type="button" class="btn btn-primary" style="margin: 5px;" value="删除音乐" οnclick="deleteMusic(\''+list.musicId+'\')">';
            s+= '<div class="player">';
            s+= '<audio id="player2" preload="none" controls style="max-width: 100%">';
            s+= '<source src="'+ list.path+'.mp3'+'" type="audio/mp3">';
            s+= '</audio></div></div></div>';
        }
        $("#list23").html(s);
      }
		
	  // 把毫秒级时间戳转化成格式化日期
      function DateFormat(timeStampMS) {
            var date = new Date(timeStampMS);
 
            var year = date.getFullYear(),
                month = date.getMonth()+1,//月份是从0开始的
                day = date.getDate(),
                hour = date.getHours(),
                min = date.getMinutes(),
                sec = date.getSeconds();
            var newTime = year + '-' +
                        (month < 10? '0' + month : month) + '-' +
                        (day < 10? '0' + day : day) + ' ' +
                        (hour < 10? '0' + hour : hour) + ':' +
                        (min < 10? '0' + min : min) + ':' +
                        (sec < 10? '0' + sec : sec);
        
            return newTime;
        }

		     
    	$(function(){
            $("#submit1").click( function(){
                var name = $("#exampleInputName2").val();
                load(name);
            });
        });

15.4 测试代码

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

16. 收藏页面 - 查询模块

16.1 使用 Mybatis 操作数据库

16.1.1 在 CollectServer 中添加代码

    public List<Music> findLoveMusicByUserId(int userId){
        return collectMapper.findLoveMusicByUserId(userId);
    }

    public List<Music> findLoveMusicByNameAndUserId(String name,int userId){
        return collectMapper.findLoveMusicByNameAndUserId(name,userId);
    }

16.1.2 在 CollectMapper 中添加代码

    /**
     * 查找用户收藏的所有音乐
     * @param userId 用户Id
     * @return 返回查询到的所有音乐
     */
    List<Music> findLoveMusicByUserId(int userId);

    /**
     * 查找用户收藏音乐中名字带有 name的音乐
     * @param name 部分名字
     * @param userId 用户Id
     * @return 返回查询到的所有音乐
     */
    List<Music> findLoveMusicByNameAndUserId(String name,int userId);

16.1.3 在 CollectMapper.xml 中添加代码


    <select id="findLoveMusicByUserId" resultType="com.example.onlinemusicserver.model.Music">
        select m.* from collect c,music m where m.musicId = c.musicId and c.userId = #{userId};
    </select>

    <select id="findLoveMusicByNameAndUserId" resultType="com.example.onlinemusicserver.model.Music">
        select m.* from collect c,music m where m.musicId = c.musicId and c.userId = #{userId} and m.title like concat('%',#{name},'%');
    </select>

16.2 向 CollectController 中添加代码

/**
 * 1. 空查询, 查找所有的收藏音乐
 * 2. 模糊查询, 查询包含部分 musicName 的所有收藏音乐
 * @param musicName
 * @param request
 * @return
 */
@RequestMapping("findLoveMusic")
public ResponseBodyMessage<List<Music>> findLoveMusic(@RequestParam(required = false) String musicName,HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if(session == null) {
        return new ResponseBodyMessage<>(-1,"当前未登录",null);
    }
    User user = (User) session.getAttribute(Constant.USER_SESSION_KEY);
    int userId = user.getUserId();

    List<Music> list = null;
    if(musicName == null) {
        list = collectServer.findLoveMusicByUserId(userId);
    }else{
        list = collectServer.findLoveMusicByNameAndUserId(musicName,userId);
    }
    return new ResponseBodyMessage<>(1,"查询成功!",list);
}

16.3 前端代码

 $(function(){load()});


      function load(musicName) {
        $.ajax({
          url: 'collect/findLoveMusic',
          method: 'POST',
          data: {"musicName":musicName},
          dataType: "json",
          success: function(data,status) {
            if(data.data!=null){
              createMusic1(data.data);
            let audios = document.querySelectorAll('#player2');
            for(let audio of audios) {
              new MediaElementPlayer(audio, {
                            pluginPath: 'https://cdn.jsdelivr.net/npm/mediaelement@4.2.7/build/',
                            shimScriptAccess: 'always',
                            success: function () {
                              let play = document.querySelector('.player');
                              play.style = "visibility: visible;";
                            }
              });
            }
            }
          }
        })
      }

      $(function(){
        $("#submit1").click( function(){
            var name = $("#exampleInputName2").val();
            load(name);
        });
    });

    function createMusic1(lists) {
        let s = '';
        for(let list of lists) {
            s+= '<div class="d-block d-md-flex podcast-entry bg-white mb-5" data-aos="fade-up">';
            s+= '<img src="images/img_1.jpg" class="image">';
            s+= '<div class="text">';
            s+= '<h3 class="font-weight-light">'+list.title+'</h3>';
            s+= '<div class="text-white mb-3"><span class="text-black-opacity-05"><small>'+list.author+'</small><span class="sep">/</span><small>'+DateFormat(list.uploadtime)+'</small></span></div>';
            s+= '<input type="button" class="btn btn-primary" style="margin: 5px;" value="取消收藏" οnclick="deleteLoveMusic(\''+list.musicId+'\')">';
            s+= '<div class="player">';
            s+= '<audio id="player2" preload="none" controls style="max-width: 100%">';
            s+= '<source src="'+ list.path+'.mp3'+'" type="audio/mp3">';
            s+= '</audio></div></div></div>';
        }
        $("#list23").html(s);
      }

    // 把毫秒级时间戳转化成格式化日期
    function DateFormat(timeStampMS) {
            var date = new Date(timeStampMS);
 
            var year = date.getFullYear(),
                month = date.getMonth()+1,//月份是从0开始的
                day = date.getDate(),
                hour = date.getHours(),
                min = date.getMinutes(),
                sec = date.getSeconds();
            var newTime = year + '-' +
                        (month < 10? '0' + month : month) + '-' +
                        (day < 10? '0' + day : day) + ' ' +
                        (hour < 10? '0' + hour : hour) + ':' +
                        (min < 10? '0' + min : min) + ':' +
                        (sec < 10? '0' + sec : sec);
        
            return newTime;
    }

16.4 测试代码

在这里插入图片描述

举报

相关推荐

0 条评论